--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apicompatanamdw/compatanalysercmd/headeranalyser/src/BBCAnalyser.cpp Tue Jan 12 14:52:39 2010 +0530
@@ -0,0 +1,3164 @@
+/*
+* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include "CmdGlobals.h"
+#ifdef __WIN__
+#pragma warning(disable:4786)
+#endif
+
+#include <assert.h>
+#include <map>
+#include <list>
+#include <string>
+#include <time.h>
+#include <xercesc/dom/DOM.hpp>
+
+#include "BBCAnalyser.h"
+#include "BBCPreAnalysis.h"
+#include "Issues.h"
+#include "ReportGenerator.h"
+#include "ReportIssue.h"
+#include "XMLUtils.h"
+#include "XMLStringConst.h"
+#include "VariableNodeAnalysis.h"
+#include "EnumNodeAnalysis.h"
+#include "FunctionNodeAnalysis.h"
+#include "TypedefNodeAnalysis.h"
+#include "OperatorFunctionNodeAnalysis.h"
+#include "UnionNodeAnalysis.h"
+#include "ClassNodeAnalysis.h"
+#include "StructNodeAnalysis.h"
+#include "NodeTypeComparator.h"
+#include "Utils.h"
+
+using namespace std;
+
+XERCES_CPP_NAMESPACE_USE
+
+
+
+struct ConstructorElement
+{
+ const XMLCHAR* iEntityName;
+ NodeAnalysis::Constructor iConstructor;
+};
+
+// Table of different node analysis constructor functions
+const ConstructorElement KConstructorTable[KEntityComparisonTableCount]=
+ {
+ {KXMLBaseString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLFundamentalTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLTypedefString,TypedefNodeAnalysis::Construct},//
+ {KXMLNamespaceString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLCvQualifiedTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLVariableString,VariableNodeAnalysis::Construct},//
+ {KXMLFundamentalTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLTypedefString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLNamespaceString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLFunctionString,FunctionNodeAnalysis::Construct},//
+ {KXMLEnumerationString,EnumNodeAnalysis::Construct},//
+ {KXMLFieldString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLArgumentString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLEllipsisString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLArrayTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLClassString,ClassNodeAnalysis::Construct},//
+ {KXMLConstructorString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLConverterString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLDestructorString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLEnumValueString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLFileString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLFunctionTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLMethodString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLMethodTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLNamespaceAliasString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLOffsetTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLOperatorFunctionString,OperatorFunctionNodeAnalysis::Construct},
+ {KXMLOperatorMethodString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLPointerTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLReferenceTypeString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLStructString,StructNodeAnalysis::Construct},
+ {KXMLUnimplementedString,UnderConstructionNodeAnalysis::Construct},
+ {KXMLUnionString,UnionNodeAnalysis::Construct}
+ };
+
+// ----------------------------------------------------------------------------
+// NodeAnalysis::FindNodeAnalysisConstructor
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis::Constructor FindNodeAnalysisConstructor(const XMLCh* nodeName)
+{
+ int i = 0;
+
+ for (i = 0;i < KEntityComparisonTableCount; ++i)
+ {
+ if ( Equals(KConstructorTable[i].iEntityName,nodeName) )
+ {
+ return KConstructorTable[i].iConstructor;
+ }
+ }
+ return NULL;
+}
+
+// ----------------------------------------------------------------------------
+// BBCPreAnalysis::preAnalyseClassForVirtuality
+//
+// Analyse for virtuality
+// ----------------------------------------------------------------------------
+//
+bool BBCPreAnalysis::preAnalyseClassForVirtuality(HANodeIterator classNode)
+{
+ bool isvirtual = false;
+ bool hasvirtualbases = false;
+
+ //Check to see if we have already inspected this class
+ if ( classNode.GetAttribute(KXMLBBCVirtualString) )
+ {
+ return classNode.CheckForBooleanAttribute(KXMLBBCVirtualString);
+ }
+
+ if ( classNode->hasChildNodes() )
+ {
+ //Check for virtual bases first as it is quicker
+ DOMNodeList * childs = classNode->getChildNodes();
+
+ XMLSize_t childcount = childs->getLength();
+
+ for (unsigned int i = 0; i < childcount; ++i)
+ {
+ DOMNode* child = childs->item(i);
+
+ //Skip any other than Base node
+ if ( !Equals(child->getNodeName(),KXMLBaseString) )
+ {
+ continue;
+ }
+
+ HANodeIterator childclass(classNode);
+ childclass.current = child;
+
+ if ( childclass.CheckForBooleanAttribute(KXMLVirtualString) )
+ {
+ classNode.SetAttribute(KXMLBBCVirtualInheritanceString,KXML1String);
+ hasvirtualbases = true;
+ }
+
+ const XMLCh * classid = childclass.GetAttribute(KXMLTypeString);
+
+ assert(classid != NULL);
+
+ bool ret = childclass.FindNodeById(classid);
+
+ assert(ret == true);
+
+ if ( preAnalyseClassForVirtuality( childclass ) )
+ {
+ //The class is virtual, mark it to the xml document and return
+ classNode.SetAttribute(KXMLBBCVirtualString, KXML1String);
+ isvirtual = true;
+ }
+
+ if ( childclass.CheckForBooleanAttribute(KXMLBBCVirtualInheritanceString) )
+ {
+ classNode.SetAttribute(KXMLBBCVirtualInheritanceString,KXML1String);
+ hasvirtualbases = true;
+ }
+ }
+
+ }
+
+ //We have already detected that this is virtual class
+ if ( isvirtual )
+ {
+ ClassGenerateVirtualTable(classNode);
+ return true;
+ }
+
+ //Go through the methods of the class and check them for virtuality
+ const XMLCh* attributeValue = classNode.GetAttribute(KXMLMembersString);
+
+ if (attributeValue)
+ {
+ BaseRefVectorOf< XMLCh > * memberids_ptr = XMLString::tokenizeString(attributeValue);
+ auto_ptr<BaseRefVectorOf< XMLCh > > memberids(memberids_ptr);
+
+ for (unsigned int i = 0; i < memberids->size(); ++i)
+ {
+ const XMLCh * memberid = memberids->elementAt(i);
+
+ HANodeIterator member(classNode);
+ bool memberfound = member.FindNodeById(memberid);
+
+ if ( memberfound )
+ {
+ if ( member.CheckForBooleanAttribute(KXMLVirtualString) ||
+ member.CheckForBooleanAttribute(KXMLPureVirtualString))
+ {
+ //Generate primary virtual table for the class
+ ClassGenerateVirtualTable(classNode);
+ //The class is virtual, mark it to the xml document and return
+ classNode.SetAttribute(KXMLBBCVirtualString, KXML1String);
+ return true;
+ }
+ }
+ else
+ {
+ //The tree is broken
+ assert(false);
+ }
+ }
+ //memberids->cleanup();
+ //delete memberids;
+ }
+
+ classNode.SetAttribute(KXMLBBCVirtualString, KXML0String);
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::preAnalyseClassForDerivability
+//
+// Check for derivability. The class is derivable iff:
+// 1. Has a public or protected explicitely declared exported constructor
+// 2. Has a public or protected inline constructor
+// In GCCXML:
+//
+// Check methods of type "Constructor"
+//
+// Constructor type / attribute:| artificial | explicit | inline | exported
+//--------------------------------------------------------------------------
+// implicite inline constructor | x | x | x |
+// inline constructor | | (x) | x |
+// exported constructor | | (x) | | x
+// ----------------------------------------------------------------------------
+//
+void BBCPreAnalysis::preAnalyseClassForDerivability(HANodeIterator classNode)
+{
+ //Go through the methods of the class and check them for constructor
+ const XMLCh* attributeValue = classNode.GetAttribute(KXMLMembersString);
+
+ //Default to public desctructor as it is same as no desctructor at all
+ classNode.SetAttribute(KXMLBBCDestructorAccessString,KXMLBBCAccessPublicString);
+
+ if (attributeValue)
+ {
+ BaseRefVectorOf< XMLCh > * memberids_ptr = XMLString::tokenizeString (attributeValue);
+ auto_ptr<BaseRefVectorOf< XMLCh > > memberids(memberids_ptr);
+
+ for (unsigned int i = 0; i < memberids->size(); ++i)
+ {
+ const XMLCh * memberid = memberids->elementAt(i);
+
+ HANodeIterator member(classNode);
+
+ if ( member.FindNodeById(memberid) )
+ {
+ //The member is constructor
+ if ( Equals(member->getNodeName(),KXMLConstructorString) )
+ {
+ //Check if the constructor is protected or public
+ const XMLCh* accessAttribute = member.GetAttribute(KXMLAccessString);
+
+ if ( Equals(accessAttribute,KXMLProtectedString) || Equals(accessAttribute,KXMLPublicString) )
+ {
+ //If the constructor is artificial (compiler generated) we need to check for the explicit attribute
+ // to recognize the proper constructor and not the helper constructor generated by the compiler
+ bool artificial = member.CheckForBooleanAttribute(KXMLArtificialString);
+
+ bool explicit_val = member.CheckForBooleanAttribute(KXMLExplicitString);
+
+ bool inline_val = member.CheckForBooleanAttribute(KXMLInlineString);
+
+ const XMLCh* attributeAttribute = member.GetAttribute(KXMLAttributeString);
+ //Check for export or inline
+ if ( ( inline_val && explicit_val && artificial ) || //the constructor is compiler generated inline function
+ ( inline_val && !artificial ) || //the constructor is explicitely declared inline function
+ (attributeAttribute && Equals(attributeAttribute,KXMLExportedString)) //the constructor is explicitely declared exported function
+ )
+ {
+ if ( Equals(accessAttribute,KXMLProtectedString) )
+ {
+ //Is derivable class. Mark the node as one.
+ classNode.SetAttribute(KXMLBBCProtectedConstructorString,KXML1String);
+ }
+
+ if ( Equals(accessAttribute,KXMLPublicString) )
+ {
+ classNode.SetAttribute(KXMLBBCPublicConstructorString,KXML1String);
+ //Class is instantiable,too!!!
+ }
+ }
+ }
+ } else if ( Equals(member->getNodeName(),KXMLDestructorString) )
+ {
+ //Check if the destructor is private, protected or public and accessibility
+ // if the desctructor is not accessible it is marked as private
+ const XMLCh* accessAttribute = member.GetAttribute(KXMLAccessString);
+
+ bool inline_val = member.CheckForBooleanAttribute(KXMLInlineString);
+ bool virtual_val = member.CheckForBooleanAttribute(KXMLVirtualString) ||
+ member.CheckForBooleanAttribute(KXMLPureVirtualString);
+ bool exported_val = false;
+ const XMLCh* attributeAttribute = member.GetAttribute(KXMLAttributeString);
+
+ if (attributeAttribute && Equals(attributeAttribute,KXMLExportedString) )
+ {
+ exported_val = true;
+ }
+
+ if ( !Equals(accessAttribute,KXMLPrivateString) && (inline_val || virtual_val || exported_val) )
+ {
+
+ if ( Equals(accessAttribute,KXMLPublicString) )
+ {
+ classNode.SetAttribute(KXMLBBCDestructorAccessString,KXMLBBCAccessPublicString);
+
+ } else if ( Equals(accessAttribute,KXMLProtectedString) )
+ {
+ classNode.SetAttribute(KXMLBBCDestructorAccessString,KXMLBBCAccessProtectedString);
+ }
+ }
+ else
+ {
+ classNode.SetAttribute(KXMLBBCDestructorAccessString,KXMLBBCAccessPrivateString);
+ }
+ }
+
+ }
+ else
+ {
+ //The tree is broken
+ assert(false);
+ }
+ }
+ //delete memberids;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::preAnalyseClassForInlineFunctions
+//
+// ----------------------------------------------------------------------------
+//
+void BBCPreAnalysis::preAnalyseClassForInlineFunctions(HANodeIterator classNode)
+{
+ //Go through the methods of the class and check them for virtuality
+ const XMLCh* attributeValue = classNode.GetAttribute(KXMLMembersString);
+
+ if (attributeValue)
+ {
+ BaseRefVectorOf< XMLCh > * memberids_ptr = XMLString::tokenizeString (attributeValue);
+ auto_ptr<BaseRefVectorOf< XMLCh > > memberids(memberids_ptr);
+ bool hasPublicInline = false;
+ bool hasProtectedInline = false;
+
+ for (unsigned int i = 0; i < memberids->size(); ++i)
+ {
+ const XMLCh * memberid = memberids->elementAt(i);
+
+ HANodeIterator member(classNode);
+
+ if ( member.FindNodeById(memberid) )
+ {
+ //Check every inline function but do not take artificial (compiler generated) functions into account
+ if ( member.CheckForBooleanAttribute(KXMLInlineString) && !member.CheckForBooleanAttribute(KXMLArtificialString) )
+ {
+
+ //Check if the constructor is protected or public
+ const XMLCh* attributeValue = member.GetAttribute(KXMLAccessString);
+
+ if ( Equals(attributeValue,KXMLProtectedString) )
+ {
+ //The class has protected inline function
+ hasProtectedInline = true;
+ classNode.SetAttribute(KXMLBBCProtectedInlineString,KXML1String);
+ }
+
+ if ( Equals(attributeValue,KXMLPublicString) )
+ {
+ //The class has public inline function
+ hasPublicInline = true;
+ classNode.SetAttribute(KXMLBBCPublicInlineString,KXML1String);
+ }
+
+ //It is enough if we have public inline, the class is fully exposed
+ if ( hasPublicInline )
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ //The tree is broken
+ assert(false);
+ }
+ }
+ //memberids->cleanup();
+ //delete memberids;
+ }
+
+}
+
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::preAnalyseClass
+//
+// ----------------------------------------------------------------------------
+//
+void BBCPreAnalysis::preAnalyseClass(HANodeIterator classNode)
+{
+ preAnalyseClassForVirtuality(classNode);
+ preAnalyseClassForDerivability(classNode);
+ preAnalyseClassForInlineFunctions(classNode);
+}
+
+
+// ----------------------------------------------------------------------------
+// printNode
+// DEBUG method
+//
+// ----------------------------------------------------------------------------
+//
+void printNode(HANodeIterator node)
+{
+ DEBUG_STUFF(const XMLCh * name = node->getNodeName();)
+ const XMLCh * value = node->getNodeValue();
+
+ DEBUG_PRINT_XMLCh(name)
+
+ if ( value )
+ {
+ DEBUG_PRINT(":")
+ DEBUG_PRINT_XMLCh(value)
+ }
+
+ DOMNamedNodeMap * atts = node->getAttributes();
+ if (atts)
+ {
+ DEBUG_PRINT(" attributes: ")
+ XMLSize_t size = atts->getLength();
+ for (unsigned int i = 0; i < size; ++i )
+ {
+ DOMNode * att = atts->item(i);
+ HANodeIterator cit(node);
+ cit.current = att;
+ printNode(cit);
+ }
+ }
+ DEBUG_PRINT("\n")
+}
+
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::preAnalyseGenerateMaps
+//
+// ----------------------------------------------------------------------------
+//
+void BBCPreAnalysis::preAnalyseGenerateMaps(HANodeIterator rootnode, bool baseline)
+{
+ //First generate the file maps
+ short nodetype = rootnode->getNodeType();
+ assert(nodetype == DOMNode::ELEMENT_NODE);
+
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Generating index*********************\n")
+ DEBUG_STUFF(time_t starttime = time(NULL);)
+#endif
+
+ DOMDocument * doc = rootnode->getOwnerDocument();
+ DOMNodeIterator * domit = doc->createNodeIterator (rootnode.current,DOMNodeFilter::SHOW_ELEMENT, NULL, true);
+ DOMNode * it = NULL;
+ while ( NULL != (it = domit->nextNode()) )
+ {
+ HANodeIterator childit(rootnode);
+ childit.current = it;
+
+#ifdef _DEBUG
+ //printNode(childit);
+ // Keep commented, too much stuff to print
+#endif
+ if (DOMNode::ELEMENT_NODE == childit->getNodeType())
+ {
+ childit.IndexNode();
+ }
+ }
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Generating index END*********************\n")
+ DEBUG_STUFF(time_t endtime = time(NULL);)
+ DEBUG_STUFF(time_t runningtime = endtime - starttime;)
+ DEBUG_PRINT("ELAPSED TIME: ")
+ DEBUG_PRINT((long)runningtime)
+ DEBUG_PRINT("\n")
+
+ DEBUG_PRINT("****************preAnalyse: Generating name map*********************\n")
+ DEBUG_STUFF(time_t starttime2 = time(NULL);)
+#endif
+
+ doc = rootnode->getOwnerDocument();
+ domit = doc->createNodeIterator (rootnode.current,DOMNodeFilter::SHOW_ELEMENT, NULL, true);
+ it = NULL;
+ while ( NULL != (it = domit->nextNode()) )
+ {
+ HANodeIterator childit(rootnode);
+ childit.current = it;
+
+ // Add node to name map if following conditions are true:
+ // 1. Node is proper i.e. it is in proper context and it is not artificial (compiler generated).
+ // 2. Node is named (class, enum, function.. etc.)
+ // 3. It is declared in the analysed header OR it is not a baseline node.
+ // Without this rule, classes that are moved to another, not to be analysed header,
+ // would not be properly analysed.
+ if (IsProperNode(childit) && IsNamedNode(childit) && (childit.toBeAnalysed() || !baseline))
+ {
+ const XMLCh* nodetype = childit->getNodeName();
+
+ if ( Equals(nodetype,KXMLEnumerationString) )
+ {
+ //Check to see if the enumeration is anonymous
+ if ( IsAnonymous(childit) )
+ {
+ DOMNodeList* enumchilds = childit.GetElementsByTagName(KXMLEnumValueString);
+ XMLSize_t enumchildcount = enumchilds->getLength();
+ unsigned int i = 0;
+ for (i = 0; i < enumchildcount; ++i)
+ {
+ HANodeIterator enumchildit(childit);
+ enumchildit.current = enumchilds->item(i);
+
+ enumchildit.NameNode(!baseline);
+
+ }
+
+ continue;//Skip the enum naming
+ }
+ }
+
+ childit.NameNode(!baseline);
+ }
+ }
+
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Generating name map END*********************\n")
+ DEBUG_STUFF(time_t endtime2 = time(NULL);)
+ DEBUG_STUFF(time_t runningtime2 = endtime2 - starttime2;)
+ DEBUG_PRINT("ELAPSED TIME: ")
+ DEBUG_PRINT((long)runningtime2)
+ DEBUG_PRINT("\n")
+#endif
+}
+
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::checkForEmptyFiles
+// ----------------------------------------------------------------------------
+//
+vector<bool> BBCAnalyser::checkForEmptyFiles(HANodeIterator rootnode, const list<string>& filesToAnalyse, const list<string>& aMacroFiles)
+{
+ DOMNodeList* childs = rootnode.GetElementsByTagName(KXMLFileString);
+ XMLSize_t childcount = childs->getLength();
+
+ vector<bool> filefound(filesToAnalyse.size(),false);
+
+ for (unsigned int i = 0; i < childcount; ++i)
+ {
+ DOMNode* child = childs->item(i);
+ HANodeIterator childit(rootnode);
+ childit.current = child;
+ const XMLCh* filename = childit.GetAttribute(KXMLNameString);
+ list<string>::const_iterator it = filesToAnalyse.begin();
+ int j = 0;
+ for (;it != filesToAnalyse.end(); ++it)
+ {
+ if ( CompareFileNames((*it),toString(filename)) )
+ {
+ filefound[j] = true;
+ break;
+ }
+ ++j;
+ }
+ }
+
+ //validate that file is not empty
+ //in case file only contained macros
+ if(!aMacroFiles.empty())
+ {
+ list<string>::const_iterator start = filesToAnalyse.begin();
+ for(unsigned int i=0; i < filesToAnalyse.size(); i++, start++)
+ {
+ if(!filefound[i])
+ {
+ list<string>::const_iterator mFiles = aMacroFiles.begin();
+ for(;mFiles != aMacroFiles.end();mFiles++)
+ if( toLowerCaseWin(*start) == *mFiles )
+ {
+ filefound[i] = true;
+ break;
+ }
+ }
+ }
+ }
+ return filefound;
+}
+
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::preAnalyse
+//
+// ----------------------------------------------------------------------------
+//
+void BBCPreAnalysis::preAnalyse(HANodeIterator rootnode,const list<string> & filesToAnalyse, bool baseline)
+{
+ short nodetype = rootnode->getNodeType();
+ assert(nodetype == DOMNode::ELEMENT_NODE);
+
+ //First generate the file maps
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Generating file maps*********************\n")
+ DEBUG_STUFF(time_t starttime = time(NULL);)
+#endif
+
+ DOMNodeList* childs = rootnode.GetElementsByTagName(KXMLFileString);
+ XMLSize_t childcount = childs->getLength();
+#ifndef NO_DBG
+ DEBUG_PRINT("preAnalyseGenerateMaps: Files to analyse: ")
+ DEBUG_PRINT(childcount)
+ DEBUG_PRINT("\n")
+#endif
+
+ unsigned int i = 0;
+ for (i = 0; i < childcount; ++i)
+ {
+ DOMNode* child = childs->item(i);
+ HANodeIterator childit(rootnode);
+ childit.current = child;
+ bool filetoanalyse = false;
+ const XMLCh* filename = childit.GetAttribute(KXMLNameString);
+ list<string>::const_iterator it = filesToAnalyse.begin();
+ int i = 0;
+ for (;it != filesToAnalyse.end(); ++it)
+ {
+ if ( CompareFileNames((*it),toString(filename)) )
+ {
+ filetoanalyse = true;
+ break;
+ }
+ ++i;
+ }
+ childit.IndexFileNode(filetoanalyse);
+ }
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Generating file maps END*********************\n")
+ DEBUG_STUFF(time_t endtime = time(NULL);)
+ DEBUG_STUFF(time_t runningtime = endtime - starttime;)
+ DEBUG_PRINT("ELAPSED TIME: ")
+ DEBUG_PRINT((long)runningtime)
+ DEBUG_PRINT("\n")
+#endif
+
+ preAnalyseGenerateMaps(rootnode,baseline);
+
+ //rootnode.iNodeIndex.DumpTables();
+
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Preanalysing classes*********************\n")
+ DEBUG_STUFF(time_t starttime2 = time(NULL);)
+ DEBUG_PRINT("preAnalyse: Nodes to analyse: ")
+ DEBUG_PRINT(childcount)
+ DEBUG_PRINT("\n")
+#endif
+
+ DOMDocument * doc = rootnode->getOwnerDocument();
+ DOMNodeIterator * domit = doc->createNodeIterator (rootnode.current,DOMNodeFilter::SHOW_ELEMENT, NULL, true);
+ DOMNode * it = NULL;
+ while ( NULL != (it = domit->nextNode()) )
+ {
+ HANodeIterator childit(rootnode);
+ childit.current = it;
+#ifdef _DEBUG
+ // printNode(childit);
+ // Keep commented, too much stuff to print
+#endif
+ const XMLCh * nodename = childit->getNodeName();
+ if ( DOMNode::ELEMENT_NODE == childit->getNodeType() && childit.toBeAnalysed() &&
+ ( Equals(nodename,KXMLClassString) || Equals(nodename,KXMLStructString)
+ || Equals(nodename,KXMLUnionString))
+ )
+ {
+ preAnalyseClass(childit);
+ }
+ }
+
+#ifndef NO_DBG
+ DEBUG_PRINT("****************preAnalyse: Preanalysing classes END*********************\n")
+ DEBUG_STUFF(time_t endtime2 = time(NULL);)
+ DEBUG_STUFF(time_t runningtime2 = endtime2 - starttime2;)
+ DEBUG_PRINT("ELAPSED TIME: ")
+ DEBUG_PRINT((long)runningtime2)
+ DEBUG_PRINT("\n")
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::nodeAnalyseTrees
+// ----------------------------------------------------------------------------
+//
+int BBCAnalyser::nodeAnalyseTrees(HANodeIterator baseline, HANodeIterator current,const list< pair<string,string> >& filesToAnalyse)
+{
+ //Find out the files to be processed
+ short nodetype = baseline->getNodeType();
+ assert(nodetype == DOMNode::ELEMENT_NODE);
+ nodetype = current->getNodeType();
+ assert(nodetype == DOMNode::ELEMENT_NODE);
+
+ int ret = 0;
+
+ DOMDocument * doc = baseline->getOwnerDocument();
+ DOMNodeIterator * domit = doc->createNodeIterator (baseline.current,DOMNodeFilter::SHOW_ELEMENT, NULL, true);
+ DOMNode * it = NULL;
+
+ while ( NULL != (it = domit->nextNode()) )
+ {
+ HANodeIterator childit(baseline);
+ childit.current = it;
+
+ if (IsNamedNode(childit) && IsProperNode(childit) && childit.toBeAnalysed())
+ {
+ if ( !CheckAccessibility(childit) )
+ {
+ //The node is not visible, so no need to analyse
+ continue;
+ }
+ HANodeIterator currentit(current);
+
+ const XMLCh* name = childit.GetAttribute(KXMLNameString);
+ if ( StartsWith(name,KXMLInternalNamePrefix) )
+ {
+ //Skip compiler generated pseudo elements
+ continue;
+ }
+
+ const XMLCh* id = childit.GetAttribute(KXMLIdString);
+ DEBUG_PRINT("Analysing:")
+ if ( name )
+ {
+ DEBUG_PRINT_XMLCh(name)
+ }
+ if ( id )
+ {
+ DEBUG_PRINT(":")
+ DEBUG_PRINT_XMLCh(id)
+ }
+ DEBUG_PRINT("\n")
+
+
+ NodeAnalysis::Constructor constructorfunction = FindNodeAnalysisConstructor(childit->getNodeName());
+ NodeAnalysis * analyser = constructorfunction();
+
+ ret += analyser->FindNodeAndAnalyse(childit,currentit);
+ delete analyser;
+ }
+ }
+
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::analyseTrees
+// ----------------------------------------------------------------------------
+//
+int BBCAnalyser::analyseTrees(DOMNode* baseline, DOMNode* current,const list< pair<string,string> >& filesToAnalyse, const list<string>& aMacroFiles)
+{
+#ifndef NO_DBG
+ DEBUG_PRINT("****************Analyse: ANALYSE starts*********************\n")
+ DEBUG_STUFF(time_t starttime = time(NULL);)
+#endif
+
+ iBaselineIndex.clear();
+ iCurrentIndex.clear();
+
+ HANodeIterator baselineit(baseline,iBaselineIndex,iReport, filesToAnalyse, true );
+ HANodeIterator currentit(current,iCurrentIndex,iReport, filesToAnalyse, false);
+
+ list<string> basefiles, currentfiles;
+ list< pair<string,string> >::const_iterator it = filesToAnalyse.begin();
+
+ for (; it != filesToAnalyse.end(); ++it)
+ {
+ basefiles.push_back((*it).first);
+ currentfiles.push_back((*it).second);
+ }
+
+ preAnalysis.preAnalyse(baselineit,basefiles,true);
+ preAnalysis.preAnalyse(currentit,currentfiles,false);
+
+ vector<bool> bfilefound;
+ bfilefound = checkForEmptyFiles(baselineit,basefiles,aMacroFiles);
+
+ vector<bool> cfilefound;
+ cfilefound = checkForEmptyFiles(currentit,currentfiles,aMacroFiles);
+
+ list<pair<string,string> >::const_iterator fileit = filesToAnalyse.begin();
+ size_t i = 0;
+
+ for (i=0;i < bfilefound.size(); ++i,++fileit)
+ {
+ if ( !cfilefound[i] && !bfilefound[i] )
+ {
+ // Serious problem, the analysed file is not in the GCCXML output
+ iReport.addIssue(fileit->first,"", EIssueIdentityFile, EIssueTypeEmpty,
+ BCseverityAccessible<EIssueIdentityFile,EIssueTypeEmpty>(true), SCseverityAccessible<EIssueIdentityFile,EIssueTypeEmpty>(true), "", 0, fileit->second, "");
+ }
+ else if ( !bfilefound[i] )
+ {
+ // Serious problem, the analysed file is not in the GCCXML output
+ iReport.addIssue(fileit->first,"", EIssueIdentityFile, EIssueTypeEmpty,
+ BCseverityAccessible<EIssueIdentityFile,EIssueTypeEmpty>(true), SCseverityAccessible<EIssueIdentityFile,EIssueTypeEmpty>(true), "", 0, fileit->second, "");
+ }
+ else if ( !cfilefound[i])
+ {
+ // Serious problem, the analysed file is not in the GCCXML output
+ iReport.addIssue(fileit->first,"", EIssueIdentityFile, EIssueTypeEmpty,
+ BCseverityAccessible<EIssueIdentityFile,EIssueTypeEmpty>(true), SCseverityAccessible<EIssueIdentityFile,EIssueTypeEmpty>(true), "", 0, fileit->second, "",false);
+ }
+ }
+
+ //baselineit.iNodeIndex.DumpTables();
+ //currentit.iNodeIndex.DumpTables();
+
+#ifndef NO_DBG
+ DEBUG_PRINT("****************nodeAnalyse: Analysing*********************\n")
+ DEBUG_STUFF(time_t starttime2 = time(NULL);)
+#endif
+
+ int ret = nodeAnalyseTrees(baselineit, currentit, filesToAnalyse);
+#ifndef NO_DBG
+ DEBUG_STUFF(time_t endtime2 = time(NULL);)
+ DEBUG_STUFF(time_t runningtime2 = endtime2- starttime2;)
+ DEBUG_PRINT("****************nodeAnalyse: Analysing END*********************\n")
+ DEBUG_PRINT("ELAPSED TIME: ")
+ DEBUG_PRINT((long)runningtime2)
+ DEBUG_PRINT("\n")
+
+ DEBUG_PRINT("****************Analyse: ANALYSE END*********************\n")
+ DEBUG_STUFF(time_t endtime = time(NULL);)
+ DEBUG_STUFF(time_t runningtime = endtime - starttime;)
+ DEBUG_PRINT("ELAPSED TIME: ")
+ DEBUG_PRINT((long)runningtime)
+ DEBUG_PRINT("\n")
+#endif
+
+ return ret;
+}
+
+
+// ----------------------------------------------------------------------------
+// BBCAnalyser::BBCAnalyser
+// ----------------------------------------------------------------------------
+//
+BBCAnalyser::BBCAnalyser(ReportGenerator & report):
+iReport(report)
+{
+}
+
+
+// ----------------------------------------------------------------------------
+// NodeAnalysis::findNode
+//
+// ----------------------------------------------------------------------------
+//
+DOMNode* NodeAnalysis::findNode(HANodeIterator nodetofind, HANodeIterator findfrom )
+{
+ DOMNode * ret = NULL;
+
+ pair<const XMLCh*,const XMLCh*> fqname = nodetofind.GetFullyQualifiedName();
+#ifndef NO_DBG
+ DEBUG_PRINT("Finding node from current three with fqname: ")
+ DEBUG_PRINT_XMLCh(fqname.first)
+ DEBUG_PRINT(" ... ")
+#endif
+
+ if ( findfrom.FindNodeByName(fqname) )
+ {
+ ret = findfrom.current;
+ }
+ return ret;
+}
+
+///////////////////////////////UnderConstructionNodeAnalysis////////////////////////////
+
+// ----------------------------------------------------------------------------
+// UnderConstructionNodeAnalysis::Construct
+//
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* UnderConstructionNodeAnalysis::Construct()
+{
+ return new UnderConstructionNodeAnalysis();
+}
+
+
+// ----------------------------------------------------------------------------
+// UnderConstructionNodeAnalysis::Analyse
+//
+// ----------------------------------------------------------------------------
+//
+int UnderConstructionNodeAnalysis::Analyse(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ assert(
+ Equals(baseline->getNodeName(), current->getNodeName())
+ );
+
+ if (report)
+ {
+ AddIssue<EIssueIdentityFile, EIssueTypeUnderConstruction>(&baseline, baseline,0);
+ }
+ return 1;
+}
+
+
+// ----------------------------------------------------------------------------
+// UnderConstructionNodeAnalysis::FindNodeAndAnalyse
+//
+// ----------------------------------------------------------------------------
+//
+int UnderConstructionNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ AddIssue<EIssueIdentityFile,EIssueTypeUnderConstruction>(&baseline,baseline,0);
+ return 1;
+}
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////VariableNodeAnalysis/////////////////////////////////////
+
+
+// ----------------------------------------------------------------------------
+// VariableNodeAnalysis::Construct
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* VariableNodeAnalysis::Construct()
+{
+ return new VariableNodeAnalysis();
+}
+
+// ----------------------------------------------------------------------------
+// VariableNodeAnalysis::FindNodeAndAnalyse
+// ----------------------------------------------------------------------------
+//
+int VariableNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ DOMNode* node = NodeAnalysis::findNode(baseline,current);
+ if ( !node )
+ {
+ AddIssue<EIssueIdentityVariable, EIssueTypeRemoval>(&baseline, baseline,0);
+ return 1;
+ }
+ current.current = node;
+
+ return this->Analyse(baseline,current);
+}
+
+
+// ----------------------------------------------------------------------------
+// VariableNodeAnalysis::Analyse
+// ----------------------------------------------------------------------------
+//
+int VariableNodeAnalysis::Analyse(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ assert( Equals(KXMLVariableString, baseline->getNodeName()) &&
+ Equals(KXMLVariableString, current->getNodeName()) &&
+ Equals(baseline->getNodeName(), current->getNodeName())
+ );
+
+ int ret = 0;
+
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ if ( IsAnonymousType(baseline) )
+ {
+ //We need to to comparison between the baseline type and current type anonymously
+
+ HANodeIterator baselinetypeit(baseline);
+ HANodeIterator currenttypeit(current);
+
+ const XMLCh* baselinetypeid = baseline.GetAttribute(KXMLTypeString);
+ const XMLCh* currenttypeid = current.GetAttribute(KXMLTypeString);
+
+ assert( baselinetypeid && currenttypeid);
+
+ bool ret1 = baselinetypeit.FindNodeById(baselinetypeid);
+ bool ret2 = currenttypeit.FindNodeById(currenttypeid);
+
+ assert(ret1 && ret2);
+
+ HANodeIterator baselinetypeanonit(baselinetypeit);
+ HANodeIterator currenttypeanonit(currenttypeit);
+ ret1 = FindAnonymousType(baselinetypeit,baselinetypeanonit);
+ ret2 = FindAnonymousType(currenttypeit,currenttypeanonit);
+
+ assert(ret1);
+
+ if ( !ret2 || !baselinetypeanonit.IsSameNodeType(currenttypeanonit) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVariable, EIssueTypeChangeInType>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+ else
+ {
+
+ NodeAnalysis::Constructor constructorfunction = FindNodeAnalysisConstructor(baselinetypeanonit->getNodeName());
+ NodeAnalysis * analyser = constructorfunction();
+ int ret = analyser->Analyse(baselinetypeanonit,currenttypeanonit,false);
+ if ( ret > 0 )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVariable, EIssueTypeChangeInType>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+ delete analyser;
+ }
+ }
+ else
+ {
+ //{KXMLTypeString,EIdAttribute}
+ if ( !CompareAttributes(baseline,current,KXMLTypeString,ETypeAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVariable, EIssueTypeChangeInType>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+ }
+
+ //{KXMLInitString,EOptionalSimpleAttribute}
+ if ( !CompareAttributes(baseline,current,KXMLInitString,EOptionalSimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVariable, EIssueTypeChangeInInitialisation>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+
+ if (!CheckAccessModifier(baseline,current))
+ {
+ if (report)
+ {
+ //AddIssue<iIdentity,EIssueTypeAccess>(&baseline, current);
+ AddIssue<EIssueIdentityVariable,EIssueTypeAccess>(&baseline, current,lineNo);
+ }
+ ret += 1;
+ }
+
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////EnumNodeAnalysis/////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// EnumNodeAnalysis::Construct
+//
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* EnumNodeAnalysis::Construct()
+{
+ return new EnumNodeAnalysis;
+}
+
+// ----------------------------------------------------------------------------
+// EnumNodeAnalysis::FindNodeAndAnalyse
+//
+// ----------------------------------------------------------------------------
+//
+int EnumNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ int ret = 0;
+ if ( IsAnonymous(baseline) )
+ {
+ DOMNodeList* enumchilds = baseline.GetElementsByTagName(KXMLEnumValueString);
+ XMLSize_t enumchildcount = enumchilds->getLength();
+ unsigned int i = 0;
+ for (i = 0; i < enumchildcount; ++i)
+ {
+ int lineNo = 0;
+ HANodeIterator enumchildit(baseline);
+ enumchildit.current = enumchilds->item(i);
+
+ DOMNode* node = NodeAnalysis::findNode(enumchildit,current);
+ if ( !node )
+ {
+ AddIssue<EIssueIdentityEnumerationValue,EIssueTypeRemoval>(&enumchildit, enumchildit, 0, baseline.GetAttribute(KXMLFileIdString));
+ ++ret;
+ continue;
+ }
+ current.current = node;
+ DOMNode* parentnode = node->getParentNode();
+ const XMLCh* lineNumber = GetAttribute(parentnode,KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ if ( !CheckEnumValue(enumchildit,current) )
+ {
+ AddIssue<EIssueIdentityEnumerationValue,EIssueTypeChangeInInitialisation>(&enumchildit, current, lineNo, baseline.GetAttribute(KXMLFileIdString));
+ ++ret;
+ }
+ HANodeIterator currentparent(current);
+ if ( FindParentContext(current, currentparent))
+ {
+ if ( !CheckAccessModifier(baseline,currentparent) )
+ {
+ AddIssue<EIssueIdentityEnumerationValue,EIssueTypeAccess>(&enumchildit, current, lineNo, baseline.GetAttribute(KXMLFileIdString));
+ ++ret;
+ }
+ }
+ }
+ }
+ else
+ {
+
+ DOMNode* node = NodeAnalysis::findNode(baseline,current);
+ if ( !node )
+ {
+ AddIssue<EIssueIdentityEnumeration,EIssueTypeRemoval>(&baseline, baseline,0);
+ return 1;
+ }
+ current.current = node;
+
+ ret += this->Analyse(baseline,current);
+ }
+ return ret;
+}
+
+
+// ----------------------------------------------------------------------------
+// EnumNodeAnalysis::CheckEnumValue
+//
+// ----------------------------------------------------------------------------
+//
+bool EnumNodeAnalysis::CheckEnumValue(HANodeIterator baseline,HANodeIterator current)
+{
+
+ return CompareNodes(baseline,current);
+}
+
+// ----------------------------------------------------------------------------
+// EnumNodeAnalysis::Analyse
+//
+// ----------------------------------------------------------------------------
+//
+int EnumNodeAnalysis::Analyse(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ assert( Equals(KXMLEnumerationString, baseline->getNodeName()) &&
+ Equals(KXMLEnumerationString, current->getNodeName()) &&
+ Equals(baseline->getNodeName(), current->getNodeName())
+ );
+
+
+ int ret = 0;
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ //{KXMLAlignString,ESimpleAttribute}
+ if ( !CompareAttributes(baseline,current,KXMLAlignString,ESimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityEnumeration,EIssueTypeAlign>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+
+ //{KXMLSizeString,ESimpleAttribute}
+ if ( !CompareAttributes(baseline,current,KXMLSizeString,ESimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityEnumeration,EIssueTypeSize>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+
+ if (!CheckAccessModifier(baseline,current))
+ {
+ if (report)
+ {
+ //AddIssue<iIdentity,EIssueTypeAccess>(&baseline, current);
+ AddIssue<EIssueIdentityEnumeration, EIssueTypeAccess>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+
+ //Check the enum values
+ DOMNodeList* baselinechilds = baseline.GetElementsByTagName(KXMLEnumValueString);
+ DOMNodeList* currentchilds = current.GetElementsByTagName(KXMLEnumValueString);
+
+ XMLSize_t baselinechildcount = baselinechilds->getLength();
+ XMLSize_t currentchildcount = currentchilds->getLength();
+
+ unsigned int i = 0;
+ for (i = 0; i < baselinechildcount; ++i)
+ {
+ HANodeIterator baselineit(baseline);
+ baselineit.current = baselinechilds->item(i);
+ unsigned int ii = 0;
+ for (ii = 0; ii < currentchildcount; ++ii)
+ {
+ HANodeIterator currentit(current);
+ currentit.current = currentchilds->item(ii);
+
+ if ( CompareAttributes(baselineit,currentit,KXMLNameString,ESimpleAttribute) )
+ {
+ if ( !CompareAttributes(baselineit,currentit,KXMLInitString,ESimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityEnumeration,EIssueTypeChange>(&baseline, current,lineNo);
+ }
+ ++ret;
+ return ret;
+ }
+ break;
+ }
+
+ }
+
+ if ( currentchildcount == ii )
+ {
+
+ if (report)
+ {
+ AddIssue<EIssueIdentityEnumerationValue,EIssueTypeRemoval>(&baseline, current,lineNo);
+ }
+ ++ret;
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////FunctionNodeAnalysis/////////////////////////////////////
+
+
+// ----------------------------------------------------------------------------
+// FunctionNodeAnalysis::FunctionNodeAnalysis
+//
+// ----------------------------------------------------------------------------
+//
+FunctionNodeAnalysis::FunctionNodeAnalysis():
+iFuncType(EIssueIdentityExportedFunction)
+{
+}
+
+// ----------------------------------------------------------------------------
+// FunctionNodeAnalysis::Construct
+//
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* FunctionNodeAnalysis::Construct()
+{
+ return new FunctionNodeAnalysis;
+}
+
+// ----------------------------------------------------------------------------
+// FunctionNodeAnalysis::FindNodeAndAnalyse
+//
+// ----------------------------------------------------------------------------
+//
+int FunctionNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ if ( baseline.CheckForBooleanAttribute(KXMLInlineString) )
+ {
+ iFuncType = EIssueIdentityInlineFunction;
+ }
+
+ //Check first if the function is exported
+ const XMLCh* attributeValue = baseline.GetAttribute(KXMLAttributeString);
+
+ if ( (iFuncType == EIssueIdentityInlineFunction) || (attributeValue && Equals(attributeValue,KXMLExportedString)) )
+ {
+ DOMNode* node = NodeAnalysis::findNode(baseline,current);
+ if ( !node )
+ {
+ //AddIssue<iFuncType,EIssueTypeRemoval>(&baseline, baseline);
+ AddIssueFunction<EIssueTypeRemoval>(&baseline,iFuncType,baseline,0);
+ return 1;
+ }
+ current.current = node;
+
+ return this->Analyse(baseline,current);
+ }
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// FunctionNodeAnalysis::Analyse
+//
+// ----------------------------------------------------------------------------
+//
+int FunctionNodeAnalysis::Analyse(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ assert(
+ Equals(baseline->getNodeName(), current->getNodeName())
+ );
+
+ int ret = 0;
+//<!ELEMENT FunctionType (Argument | Ellipsis)*>
+//<!ATTLIST FunctionType attributes CDATA #IMPLIED>
+//<!ATTLIST FunctionType id ID #REQUIRED>
+//<!ATTLIST FunctionType returns IDREF #REQUIRED>
+
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ const XMLCh* attributeValue = current.GetAttribute(KXMLAttributeString);
+ if (
+ (
+ (iFuncType == EIssueIdentityInlineFunction) && !current.CheckForBooleanAttribute(KXMLInlineString)
+ ) ||
+ (
+ (iFuncType == EIssueIdentityExportedFunction) && (!attributeValue || !Equals(attributeValue,KXMLExportedString) )
+ &&
+ (!current.CheckForBooleanAttribute(KXMLVirtualString))
+ )
+ )
+ {
+ if (report)
+ {
+ AddIssueFunction<EIssueTypeRemoval>(&baseline,iFuncType,baseline,0);
+
+ }
+ ++ret;
+ return ret;
+ }
+
+ string basefuncsig = GenerateFunctionSignature(baseline);
+ string currentfuncsig = GenerateFunctionSignature(current);
+
+ if ( basefuncsig != currentfuncsig )
+ {
+ ++ret;
+ if (report)
+ {
+ AddIssueFunction<EIssueTypeParam>(&baseline,iFuncType,current,lineNo);
+ }
+ }
+ else
+ {
+ //Check also the default parameter values
+ DOMElement * baselineelement = static_cast<DOMElement*>(baseline.current);
+ DOMNodeList* baselinechilds = baselineelement->getChildNodes();
+ DOMElement * currentelement = static_cast<DOMElement*>(current.current);
+ DOMNodeList* currentchilds = currentelement->getChildNodes();
+
+ XMLSize_t childcount = baselinechilds->getLength();
+
+ unsigned int i = 0;
+ for (i = 0; i < childcount; ++i)
+ {
+ DOMNode* baselinechild = baselinechilds->item(i);
+ HANodeIterator baselinechildit(baseline);
+ baselinechildit.current = baselinechild;
+
+ DOMNode* currentchild = currentchilds->item(i);
+ HANodeIterator currentchildit(current);
+ currentchildit.current = currentchild;
+
+ short nodetype = baselinechildit->getNodeType();
+ if (nodetype == DOMNode::ELEMENT_NODE)
+ {
+ const XMLCh * baselinesize = FindAttributeValueForType(baselinechildit,KXMLSizeString);
+ const XMLCh * currentsize = FindAttributeValueForType(currentchildit,KXMLSizeString);
+
+ const XMLCh * baselinealign = FindAttributeValueForType(baselinechildit,KXMLAlignString);
+ const XMLCh * currentalign = FindAttributeValueForType(currentchildit,KXMLAlignString);
+
+ if ( !baselinesize )
+ {
+ baselinesize = baselinealign;
+ }
+
+ if ( !currentsize )
+ {
+ currentsize = currentalign;
+ }
+
+ if ( !Equals(baselinesize,currentsize) || !Equals(baselinealign, currentalign) ||
+ !CompareAttributes(baselinechildit,currentchildit,KXMLDefaultString,EOptionalSimpleAttribute))
+ {
+ ++ret;
+ if (report)
+ {
+ //AddIssue<iFuncType,EIssueTypeParam>(&baseline, current);
+ AddIssueFunction<EIssueTypeParam>(&baseline,iFuncType,current,lineNo);
+ }
+ break;
+ }
+ }
+
+ }
+
+ }
+
+ if ( !CompareAttributes(baseline,current,KXMLReturnsString,EOptionalTypeAttribute) )
+ {
+ ++ret;
+ if (report)
+ {
+ AddIssueFunction<EIssueTypeReturn>(&baseline,iFuncType,current,lineNo);
+ }
+ }
+
+ return ret;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////TypedefNodeAnalysis/////////////////////////////////////
+
+
+// ----------------------------------------------------------------------------
+// TypedefNodeAnalysis::Construct
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* TypedefNodeAnalysis::Construct()
+{
+ return new TypedefNodeAnalysis;
+}
+
+// ----------------------------------------------------------------------------
+// TypedefNodeAnalysis::FindNodeAndAnalyse
+// ----------------------------------------------------------------------------
+//
+int TypedefNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ DOMNode* node = NodeAnalysis::findNode(baseline,current);
+ if ( !node )
+ {
+ AddIssue<EIssueIdentityTypedef,EIssueTypeRemoval>(&baseline, baseline,0);
+ return 1;
+ }
+ current.current = node;
+
+ return this->Analyse(baseline,current);
+}
+
+// ----------------------------------------------------------------------------
+// TypedefNodeAnalysis::Analyse
+// ----------------------------------------------------------------------------
+//
+int TypedefNodeAnalysis::Analyse(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ assert( Equals(KXMLTypedefString, baseline->getNodeName()) &&
+ Equals(KXMLTypedefString, current->getNodeName()) &&
+ Equals(baseline->getNodeName(), current->getNodeName())
+ );
+
+ //<Typedef id="_9" name="TOmaInt" type="_8" context="_1" location="f0:108" file="f0" line="108"/>
+
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ int ret = 0;
+
+ if ( !CompareAttributes(baseline,current,KXMLNameString,ESimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityTypedef,EIssueTypeChange>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+
+ if ( !CompareAttributes(baseline,current,KXMLTypeString,ETypeAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityTypedef,EIssueTypeChange>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+
+ HANodeIterator baselinetypeit(baseline);
+ HANodeIterator currenttypeit(current);
+
+ const XMLCh* baselinetypeid = baseline.GetAttribute(KXMLTypeString);
+ const XMLCh* currenttypeid = current.GetAttribute(KXMLTypeString);
+
+ assert( baselinetypeid && currenttypeid);
+
+ bool ret1 = baselinetypeit.FindNodeById(baselinetypeid);
+ bool ret2 = currenttypeit.FindNodeById(currenttypeid);
+
+ assert(ret1 && ret2);
+
+ if ( IsFunction(baselinetypeit) )
+ {
+ if ( !CompareAttributes(baselinetypeit,currenttypeit,KXMLReturnsString,EOptionalTypeAttribute) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityTypedef,EIssueTypeChange>(&baseline, current,lineNo);
+ }
+ ++ret;
+ }
+ }
+
+ if (!CheckAccessModifier(baseline,current))
+ {
+ if (report)
+ {
+ //AddIssue<iIdentity,EIssueTypeAccess>(&baseline, current);
+ AddIssue<EIssueIdentityTypedef,EIssueTypeAccess>(&baseline, current,lineNo);
+ }
+ ret += 1;
+ }
+
+ return ret;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////OperatorFunctionNodeAnalysis/////////////////////////////
+
+// ----------------------------------------------------------------------------
+// OperatorFunctionNodeAnalysis::Construct
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* OperatorFunctionNodeAnalysis::Construct()
+{
+ return new OperatorFunctionNodeAnalysis;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////UnionNodeAnalysis////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// UnionNodeAnalysis::Construct
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* UnionNodeAnalysis::Construct()
+{
+ return new UnionNodeAnalysis;
+}
+
+// ----------------------------------------------------------------------------
+// UnionNodeAnalysis::UnionNodeAnalysis
+//
+// ----------------------------------------------------------------------------
+//
+UnionNodeAnalysis::UnionNodeAnalysis()
+{
+ iIdentity = EIssueIdentityUnion;
+}
+
+// ----------------------------------------------------------------------------
+// UnionNodeAnalysis::compareBaseSizes
+// ----------------------------------------------------------------------------
+//
+int UnionNodeAnalysis::compareBaseSizes(HANodeIterator baseline, HANodeIterator current, const NodeIndex::dtable_t& bfields, const NodeIndex::dtable_t& cfields, bool report)
+{
+ //Not meaningful in union as it can not be derived
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// UnionNodeAnalysis::FindNodeAndAnalyse
+// ----------------------------------------------------------------------------
+//
+int UnionNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ //First check to see if this is an anonymous Union
+ const XMLCh* name = baseline.GetAttribute(KXMLNameString);
+ if ( !name )
+ {
+ //This is anonymous union and does not need to be analysed
+ return 0;
+ }
+
+ if ( Equals(name,KXMLEmptyString) )
+ {
+ return 0;
+ }
+
+ DOMNode* node = NodeAnalysis::findNode(baseline,current);
+
+ if ( !node )
+ {
+ AddIssue<EIssueIdentityUnion,EIssueTypeRemoval>(&baseline, baseline,0);
+ return 1;
+ }
+ current.current = node;
+
+ return this->Analyse(baseline,current);
+}
+
+// ----------------------------------------------------------------------------
+// UnionNodeAnalysis::compareVirtualFunctions
+// The union can not have virtual functions
+// ----------------------------------------------------------------------------
+//
+int UnionNodeAnalysis::compareVirtualFunctions(HANodeIterator baseline,HANodeIterator current,
+ const vector<DOMNode*>& bvirtualMethods,
+ const vector<DOMNode*>& cvirtualMethods,
+ bool report)
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////ClassNodeAnalysis////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// printMember
+// Debug stuff
+// ----------------------------------------------------------------------------
+//
+void printMember(HANodeIterator member)
+{
+ DEBUG_PRINT_XMLCh(member->getNodeName());
+ DEBUG_PRINT(":");
+ const XMLCh * memname = member.GetAttribute(KXMLNameString);
+ if (memname)
+ {
+ DEBUG_PRINT_XMLCh(memname);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareMethodsSignature
+// Compare baseline and current methods and return false if they do not match.
+// Uses additional comparator object if available.
+// ----------------------------------------------------------------------------
+//
+bool ClassNodeAnalysis::compareMethodsSignature(HANodeIterator basemethod,HANodeIterator currentmethod, const NodeTypeComparator& comparator)
+{
+ short basenodetype = basemethod->getNodeType();
+ short currnodetype = currentmethod->getNodeType();
+ assert(basenodetype == DOMNode::ELEMENT_NODE && currnodetype == DOMNode::ELEMENT_NODE);
+ assert(IsFunction(basemethod) && IsFunction(currentmethod));
+
+#ifdef _DEBUG
+ string basefuncsig = GenerateFunctionSignature(basemethod);
+ string currentfuncsig = GenerateFunctionSignature(currentmethod);
+ cout << " basefuncsig=" << basefuncsig << endl;
+ cout << "currentfuncsig=" << currentfuncsig << endl;
+#endif
+
+ if( !Equals(basemethod->getNodeName(), currentmethod->getNodeName() ))
+ {
+ return false;
+ }
+
+ const XMLCh* basenameatt = basemethod.GetAttribute(KXMLNameString);
+ const XMLCh* currnameatt = currentmethod.GetAttribute(KXMLNameString);
+
+ if( !Equals(basenameatt, currnameatt ))
+ {
+ return false;
+ }
+
+ DOMElement * basenodeelement = static_cast<DOMElement*>(basemethod.current);
+ DOMElement * currnodeelement = static_cast<DOMElement*>(currentmethod.current);
+ std::vector<DOMNode*> baseElementNodes;
+ std::vector<DOMNode*> currElementNodes;
+ GetElementNodes(basemethod, basenodeelement->getChildNodes(), baseElementNodes);
+ GetElementNodes(currentmethod, currnodeelement->getChildNodes(), currElementNodes);
+
+ if( baseElementNodes.size() != currElementNodes.size() )
+ {
+ return false;
+ }
+
+ for(size_t i = 0; i < baseElementNodes.size(); ++i)
+ {
+ DOMNode* basechild = baseElementNodes[i];
+ DOMNode* currchild = currElementNodes[i];
+ HANodeIterator basechildit(basemethod);
+ HANodeIterator currchildit(currentmethod);
+ basechildit.current = basechild;
+ currchildit.current = currchild;
+
+ short basetype = basechildit->getNodeType();
+ short currtype = currchildit->getNodeType();
+ if( !comparator.CompareParameter(basechildit, currchildit) )
+ {
+ return false;
+ }
+ }
+
+ if( !comparator.CompareConstness(basemethod, currentmethod) )
+ {
+ return false;
+ }
+
+ return true;
+}
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareMethodsReturn
+// ----------------------------------------------------------------------------
+//
+bool ClassNodeAnalysis::compareMethodsReturn(HANodeIterator basemethod,HANodeIterator currentmethod, NodeTypeComparator& cmp)
+{
+ return cmp.CompareReturnValue(basemethod, currentmethod);
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareField
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareField(HANodeIterator baseline, HANodeIterator current, const DataMember& basemember,const DataMember& currentmember, bool report)
+{
+ //<!ATTLIST Field mutable (0 | 1) "0">
+ //<!ATTLIST Field name CDATA #REQUIRED>
+ //<!ATTLIST Field offset CDATA #IMPLIED>
+ //<!ATTLIST Field type CDATA #REQUIRED>
+ int ret = 0;
+
+ HANodeIterator basefield(baseline);
+ basefield.current = basemember.iNode;
+ HANodeIterator currentfield(current);
+ currentfield.current = currentmember.iNode;
+
+ int baseoffset = basemember.iOffset;
+ int currentoffset = currentmember.iOffset;
+
+ TIssueIdentity identity = EIssueIdentityField;
+ bool accessthroughinline = false;
+
+ if ( !CheckAccessibility(baseline,accessthroughinline,basemember.iAccess) )
+ {
+ identity = EIssueIdentityFieldInaccessible;
+ } else
+ {
+
+ if ( baseoffset != currentoffset )
+ {
+ ret++;
+ if ( report )
+ {
+ AddIssueField<EIssueTypeOffset>(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember);
+ }
+ else
+ {
+ return ret;
+ }
+
+ }
+ }
+
+ if ( IsAnonymousType(basefield) )
+ {
+ //We need to do comparison between the baseline type and current type anonymously
+
+ HANodeIterator baselinetypeit(basefield);
+ HANodeIterator currenttypeit(currentfield);
+
+ const XMLCh* baselinetypeid = basefield.GetAttribute(KXMLTypeString);
+ const XMLCh* currenttypeid = currentfield.GetAttribute(KXMLTypeString);
+
+ assert( baselinetypeid && currenttypeid);
+
+ bool ret1 = baselinetypeit.FindNodeById(baselinetypeid);
+ bool ret2 = currenttypeit.FindNodeById(currenttypeid);
+
+ assert(ret1 && ret2);
+
+ HANodeIterator baselinetypeanonit(baselinetypeit);
+ HANodeIterator currenttypeanonit(currenttypeit);
+ ret1 = FindAnonymousType(baselinetypeit,baselinetypeanonit);
+ ret2 = FindAnonymousType(currenttypeit,currenttypeanonit);
+
+ assert(ret1);
+
+ if ( !ret2 || !baselinetypeanonit.IsSameNodeType(currenttypeanonit) )
+ {
+ if (report)
+ {
+ AddIssueField<EIssueTypeChangeInType>(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember);
+ }
+ ret++;
+ }
+ else
+ {
+ bool report2 = false;
+
+ if ( Equals(KXMLUnionString, baselinetypeit->getNodeName()) && Equals(KXMLEmptyString, basefield.GetAttribute(KXMLNameString)) )
+ {
+ report2 = report;
+ }
+
+ NodeAnalysis::Constructor constructorfunction = FindNodeAnalysisConstructor(baselinetypeanonit->getNodeName());
+ NodeAnalysis * analyser = constructorfunction();
+ int retval2 = analyser->Analyse(baselinetypeanonit,currenttypeanonit,report2);
+ if ( retval2 > 0 && !report2)
+ {
+ if (report)
+ {
+ AddIssueField<EIssueTypeChangeInType>(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember);
+ }
+ ++ret;
+ }
+ delete analyser;
+ }
+ }
+ else
+ {
+ //{KXMLTypeString,EIdAttribute}
+ if ( !CompareAttributes(basefield,currentfield,KXMLTypeString,ETypeAttribute) )
+ {
+ ret++;
+ if ( report )
+ {
+ AddIssueField<EIssueTypeChangeInType>(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember);
+ }
+ else
+ {
+ return ret;
+ }
+ }else //Check if the size has changed although the the type has remained same
+ {
+ const XMLCh* basefieldsize = GetSize(basefield);
+ const XMLCh* currentfieldsize = GetSize(currentfield);
+
+ if ( !Equals(basefieldsize,currentfieldsize) )
+ {
+ ret++;
+ if ( report )
+ {
+ AddIssueField<EIssueTypeSize>(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+
+ }
+ }
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// dumpNodeVectordumpNodeVector
+// ----------------------------------------------------------------------------
+//
+void dumpNodeVector(HANodeIterator node,const vector<DOMNode*> & nodes)
+{
+ DEBUG_PRINT("Dumping node vector:\n")
+ vector<DOMNode*>::const_iterator it = nodes.begin();
+ for (;it != nodes.end(); ++it)
+ {
+ node.current = (*it);
+
+ DEBUG_PRINT_XMLCh(node->getNodeName())
+ const XMLCh * name = node.GetAttribute(KXMLNameString);
+ if (name)
+ {
+ DEBUG_PRINT(":")
+ DEBUG_PRINT_XMLCh(name)
+ }
+ const XMLCh * id = node.GetAttribute(KXMLIdString);
+ if (id)
+ {
+ DEBUG_PRINT(" with id ")
+ DEBUG_PRINT_XMLCh(id)
+ }
+ DEBUG_PRINT("\n")
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareNonvirtualFunctions
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareNonvirtualFunctions( HANodeIterator baseline,
+ HANodeIterator current,
+ const vector<DOMNode*>& bexportedMethods,
+ const vector<DOMNode*>& cexportedMethods,
+ TIssueIdentity identity,
+ bool report )
+{
+ int ret = 0;
+ int parentLineNo = 0;
+
+ // Get default comparator:
+ const ComparatorVector& cmps = ComparatorFactory::Instance().GetComparators();
+ ComparatorVector::const_iterator comparator = cmps.begin();
+ const XMLCh* parenLinenumber = current.GetAttribute( KXMLLineString);
+ parentLineNo = atoi(toString(parenLinenumber).c_str());
+
+ // Build method maps for baseline and current platform's classes:
+ MethodMatchMap baseMap;
+ vector<DOMNode*>::const_iterator i = bexportedMethods.begin();
+ for( ; i != bexportedMethods.end(); ++i )
+ {
+ baseMap.insert( make_pair(*i, MethodMatchFlags(false, false)));
+ }
+
+ vector<DOMNode*>::const_iterator j = cexportedMethods.begin();
+ MethodMatchMap currMap;
+ for( ; j != cexportedMethods.end(); ++j )
+ {
+ currMap.insert( make_pair(*j, MethodMatchFlags(false, false)));
+ }
+
+ if( comparator != cmps.end() )
+ {
+ int comparatorRound = 1;
+ // Call compare function and give the default comparator as a parameter
+ ret = this->compareNonvirtualFunctions(baseline, current, bexportedMethods, cexportedMethods, identity, report, comparator, baseMap, currMap, comparatorRound);
+ }
+
+ if( report )
+ {
+ MethodMatchMap::iterator baseFunc = baseMap.begin();
+ for(; baseFunc != baseMap.end(); ++baseFunc )
+ {
+ int lineNo = 0;
+ string baseMethodName = toString(GetAttribute(baseFunc->first,KXMLNameString));
+ MethodMatchMap::iterator curFunc = currMap.begin();
+ for(; curFunc != currMap.end(); ++curFunc )
+ {
+ string curMethodName = toString(GetAttribute(curFunc->first,KXMLNameString));
+ if (baseMethodName == curMethodName)
+ {
+ const XMLCh* linenumber = GetAttribute(curFunc->first, KXMLLineString);
+ lineNo = atoi(toString(linenumber).c_str());
+ break;
+
+ }
+ }
+ if( baseFunc->second.signatureMatch == false )
+ {
+ // Function signatures do not match
+ HANodeIterator removedMethod(baseline);
+ removedMethod.current = baseFunc->first;
+ AddIssueFunction<EIssueTypeRemoval>(&removedMethod, identity, removedMethod,parentLineNo);
+ ++ret;
+ }
+ else if( baseFunc->second.returnValueMatch == false )
+ {
+ // Function return values do not match
+ HANodeIterator removedMethod(baseline);
+ removedMethod.current = baseFunc->first;
+ AddIssueFunction<EIssueTypeReturn>(&removedMethod,identity, removedMethod,lineNo);
+ ++ret;
+ }
+ }
+ }
+ return ret;
+}
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareNonvirtualFunctions
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareNonvirtualFunctions(
+ HANodeIterator baseline,
+ HANodeIterator current,
+ const vector<DOMNode*>& bexportedMethods,
+ const vector<DOMNode*>& cexportedMethods,
+ TIssueIdentity identity,
+ bool report,
+ ComparatorVector::const_iterator comparator,
+ MethodMatchMap& baseMap,
+ MethodMatchMap& currMap,
+ int comparatorRound)
+{
+ int ret = 0;
+
+ int lineNo1 = 0;
+ //const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ //lineNo = atoi(toString(lineNumber).c_str());
+
+ //Exported methods
+ vector<DOMNode*>::const_iterator bIter = bexportedMethods.begin();
+ for( ; bIter != bexportedMethods.end(); ++bIter )
+ {
+ MethodMatchMap::iterator baseMapIter = baseMap.find(*bIter);
+ assert(baseMapIter != baseMap.end());
+ if( baseMapIter->second.signatureMatch )
+ {
+ continue; // This method has already been found and analyzed.
+ }
+ HANodeIterator basemethod(baseline);
+ basemethod.current = *bIter;
+
+ //Check the accessibility
+ if ( CheckAccessibility(basemethod) )
+ {
+ vector<DOMNode*>::const_iterator cIter = cexportedMethods.begin();
+
+ for( ; cIter != cexportedMethods.end(); ++cIter)
+ {
+ HANodeIterator currentmethod(current);
+ currentmethod.current = *cIter;
+ const XMLCh* lineNumber1 = GetAttribute(currentmethod.current,KXMLLineString);
+ lineNo1 = atoi(toString(lineNumber1).c_str());
+
+ MethodMatchMap::iterator currMapIter = currMap.find(*cIter);
+
+ if( currMapIter != currMap.end() &&
+ currMapIter->second.signatureMatch == false &&
+ compareMethodsSignature(basemethod, currentmethod, **comparator) )
+ {
+ if( comparatorRound==CONSTFILTER_COMPARATOR )
+ {
+ // if one of the parameter has changed from non-const to const
+ ret++;
+ if(report)
+ {
+ //add the issue as it is a source compatibility break
+ AddIssueFunction<EIssueTypeParamConst>(&basemethod,identity,currentmethod,lineNo1);
+ }
+
+ //make signature and return value true so that the issue is not reported again
+ if( baseMapIter != baseMap.end() )
+ baseMapIter->second.signatureMatch = true;
+ currMapIter->second.signatureMatch = true;
+
+ baseMapIter->second.returnValueMatch = true;
+ currMapIter->second.returnValueMatch = true;
+ break;
+ }
+
+ else if( comparatorRound==CONSTFILTER2_COMPARATOR )
+ {
+ // if one of the parameter has changed from const to non-const
+ ret++;
+ if(report)
+ {
+ //add the issue as it is a source compatibility break
+ AddIssueFunction<EIssueTypeParamConst2>(&basemethod,identity,currentmethod,lineNo1);
+ }
+
+ //make signature and return value true so that the issue is not reported again
+ if( baseMapIter != baseMap.end() )
+ baseMapIter->second.signatureMatch = true;
+ currMapIter->second.signatureMatch = true;
+
+ baseMapIter->second.returnValueMatch = true;
+ currMapIter->second.returnValueMatch = true;
+ break;
+ }
+
+ if( baseMapIter != baseMap.end() )
+ baseMapIter->second.signatureMatch = true;
+ currMapIter->second.signatureMatch = true;
+ //Check also the default parameter values
+ DOMElement * baselineelement = static_cast<DOMElement*>(basemethod.current);
+ DOMNodeList* baselinechilds = baselineelement->getChildNodes();
+ DOMElement * currentelement = static_cast<DOMElement*>(currentmethod.current);
+ DOMNodeList* currentchilds = currentelement->getChildNodes();
+
+ XMLSize_t childcount = baselinechilds->getLength();
+
+ unsigned int i = 0;
+ for (i = 0; i < childcount; ++i)
+ {
+ DOMNode* baselinechild = baselinechilds->item(i);
+ HANodeIterator baselinechildit(baseline);
+ baselinechildit.current = baselinechild;
+
+ DOMNode* currentchild = currentchilds->item(i);
+ HANodeIterator currentchildit(current);
+ currentchildit.current = currentchild;
+
+ short nodetype = baselinechildit->getNodeType();
+ if (nodetype == DOMNode::ELEMENT_NODE)
+ {
+ const XMLCh * baselinesize = FindAttributeValueForType(baselinechildit,KXMLSizeString);
+ const XMLCh * currentsize = FindAttributeValueForType(currentchildit,KXMLSizeString);
+
+ const XMLCh * baselinealign = FindAttributeValueForType(baselinechildit,KXMLAlignString);
+ const XMLCh * currentalign = FindAttributeValueForType(currentchildit,KXMLAlignString);
+
+ if ( !baselinesize )
+ {
+ baselinesize = baselinealign;
+ }
+
+ if ( !currentsize )
+ {
+ currentsize = currentalign;
+ }
+
+ if ( !Equals(baselinesize,currentsize) || !Equals(baselinealign, currentalign) ||
+ !CompareAttributes(baselinechildit,currentchildit,KXMLDefaultString,EOptionalSimpleAttribute))
+ {
+ ++ret;
+ if (report)
+ {
+ AddIssueFunction<EIssueTypeParam>(&basemethod,identity,currentmethod,lineNo1);
+ }
+ break;
+ }
+ }
+ }
+
+ // Check function return values
+ const ComparatorVector& cmps = ComparatorFactory::Instance().GetComparators();
+ ComparatorVector::const_iterator retComparator = cmps.begin();
+ int retComparatorRound = 1;
+ for ( ; retComparator != cmps.end(); retComparator++ )
+ {
+ if ( compareMethodsReturn(basemethod,currentmethod, **retComparator) )
+ {
+ if( retComparatorRound==CONSTFILTER_COMPARATOR )
+ {
+ // if the return value has changed from const to non-const
+ ret++;
+ if(report)
+ {
+ //add the issue as it is a source compatibility break
+ AddIssueFunction<EIssueTypeReturnConst>(&basemethod,identity,currentmethod,lineNo1);
+ }
+ }
+ else if( retComparatorRound==CONSTFILTER2_COMPARATOR )
+ {
+ // if the return calue has changed from non-const to const
+ ret++;
+ if(report)
+ {
+ //add the issue as it is a source compatibility break
+ AddIssueFunction<EIssueTypeReturnConst2>(&basemethod,identity,currentmethod,lineNo1);
+ }
+ }
+
+ baseMapIter->second.returnValueMatch = true;
+ currMapIter->second.returnValueMatch = true;
+ break;
+ }
+ retComparatorRound++;
+ }
+
+
+ if ( !CheckAccessModifier(basemethod,currentmethod) )
+ {
+ if (report)
+ {
+ AddIssueFunction<EIssueTypeAccess>(&basemethod,identity, currentmethod,lineNo1);
+ }
+ ++ret;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Not accessible, can be marked as matching.
+ if( baseMapIter != baseMap.end() )
+ {
+ baseMapIter->second.signatureMatch = true;
+ baseMapIter->second.returnValueMatch = true;
+ }
+ }
+ }
+
+ // Recursive call with next comparator (if any) and updated method maps.
+ const ComparatorVector& cmps = ComparatorFactory::Instance().GetComparators();
+ if( ++comparator != cmps.end() )
+ {
+ comparatorRound++;
+ ret += ClassNodeAnalysis::compareNonvirtualFunctions(
+ baseline,
+ current,
+ bexportedMethods,
+ cexportedMethods,
+ identity,
+ report,
+ comparator,
+ baseMap,
+ currMap,
+ comparatorRound);
+ }
+
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareOthers
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareOthers(HANodeIterator baseline,HANodeIterator current,
+ const vector<DOMNode*>& bothers, const vector<DOMNode*>& cothers,
+ bool report)
+{
+ int retval = 0;
+ return retval;
+}
+
+// ----------------------------------------------------------------------------
+// printlist
+// ----------------------------------------------------------------------------
+//
+void printlist(const NodeIndex::dtable_t& lista)
+{
+ NodeIndex::dtable_t::const_iterator it = lista.begin();
+ for (; it != lista.end(); ++it)
+ {
+ cout << it->iName << " at " << it->iOffset << "with node:" << it->iNode << endl;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareFields
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareFields(HANodeIterator baseline,HANodeIterator current,
+ const vector<DOMNode*>& bfields_class,
+ const vector<DOMNode*>& cfields_class,
+ bool report)
+{
+ int ret = 0;
+
+ const NodeIndex::dtable_t& bfields = ClassGenerateDataMemberTable(baseline);
+ const NodeIndex::dtable_t& cfields = ClassGenerateDataMemberTable(current);
+
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ // If you don't like to see the issue about base size when the size has changed
+ // uncomment the test below
+
+ //if (!iReportAddedMembers)
+ //{
+ // Check only if size has not changed
+ ret += compareBaseSizes(baseline, current, bfields, cfields, report);
+ //}
+
+ // Fields
+ // Order and type of accessible members matters
+ //////////////////////////////////////////////////////////////
+ vector<bool> fieldFound(cfields.size(),false);
+ vector<bool> fieldRemoved(bfields.size(),false);
+ vector<bool> fieldChanged(bfields.size(),false);
+ vector<int> fieldChangedCurrent(bfields.size(),-1);
+ vector<bool> fieldAccessible(bfields.size(),false);
+
+ unsigned int i = 0;
+ for (i=0; i < bfields.size(); ++i)
+ {
+ if ( !bfields[i].iNode )
+ {
+ unsigned int ii = 0;
+ for (ii=0; ii < cfields.size(); ++ii)
+ {
+ if ( !fieldFound[ii] && (bfields[i].iName == cfields[ii].iName) )
+ {
+ fieldFound[ii] = true;
+
+ if ( bfields[i].iOffset != cfields[ii].iOffset )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualTablePointer,EIssueTypeOffset>(&baseline,current,lineNo,NULL,bfields[i]);
+ }
+ ++ret;
+ }
+ break;
+ }
+ }
+
+ if ( cfields.size() == ii )
+ {
+ fieldRemoved[i] = true;
+ }
+
+ continue;
+ }
+
+ HANodeIterator basefield(baseline);
+ basefield.current = bfields[i].iNode;
+ bool dummy;
+ fieldAccessible[i] = CheckAccessibility(baseline, dummy, bfields[i].iAccess);
+
+ unsigned int ii = 0;
+ for (ii=0; ii < cfields.size(); ++ii)
+ {
+ HANodeIterator currentfield(current);
+ currentfield.current = cfields[ii].iNode;
+
+ if ( !fieldFound[ii] && (bfields[i].iName == cfields[ii].iName) )//CompareNames(basefield,currentfield) )
+ {
+ fieldFound[ii] = true;
+
+ if ( fieldAccessible[i] && !CheckAccessModifier(bfields[i].iAccess,cfields[ii].iAccess) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityField,EIssueTypeAccess>(&baseline, currentfield,cfields[ii].iLineNo,NULL,bfields[i]);
+ }
+ ++ret;
+ }
+
+ if ( 0 != compareField(baseline,current,bfields[i],cfields[ii],false) )
+ {
+ fieldChanged[i] = true;
+ fieldChangedCurrent[i] = ii;
+ if (fieldAccessible[i])
+ {
+ iReportAddedMembers = true;
+ }
+ }
+ break;
+ }
+ }
+
+ if ( cfields.size() == ii )
+ {
+ fieldRemoved[i] = true;
+ if ( fieldAccessible[i] )
+ {
+ iReportAddedMembers = true;
+ }
+ }
+ }
+
+ for (i = 0; i < fieldRemoved.size(); ++i)
+ {
+ if (fieldRemoved[i])
+ {
+ if ( !bfields[i].iNode )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualTablePointer,EIssueTypeRemoval>(&baseline,current,lineNo,NULL,bfields[i]);
+ }
+ continue;
+ }
+
+ HANodeIterator basefield(baseline);
+ basefield.current = bfields[i].iNode;
+
+ if (iReportAddedMembers || fieldAccessible[i])
+ {
+ if (report)
+ {
+ if (fieldAccessible[i])
+ {
+ AddIssue<EIssueIdentityField,EIssueTypeRemoval>(&baseline, basefield,lineNo,NULL,bfields[i]);
+ }
+ else
+ {
+ AddIssue<EIssueIdentityFieldInaccessible,EIssueTypeRemoval>(&baseline, basefield,lineNo,NULL,bfields[i]);
+ }
+ }
+ ++ret;
+ }
+ }
+
+ if (fieldChanged[i])
+ {
+ HANodeIterator basefield(baseline);
+ HANodeIterator currentfield(current);
+ basefield.current = bfields[i].iNode;
+ int ii = fieldChangedCurrent[i];
+
+ if ( -1 == ii )
+ {
+ continue;
+ }
+
+ if (iReportAddedMembers || fieldAccessible[i])
+ {
+ if (report)
+ {
+ compareField(baseline, current, bfields[i], cfields[ii], report);
+ }
+ ++ret;
+ }
+ }
+
+ }
+
+ for (i = 0; i < fieldFound.size(); ++i)
+ {
+ if (!fieldFound[i])
+ {
+ if ( !cfields[i].iNode )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualTablePointer,EIssueTypeAddition>(&baseline,current,lineNo,NULL,cfields[i]);
+ }
+ continue;
+ }
+
+ HANodeIterator currentfield(current);
+ currentfield.current = cfields[i].iNode;
+ if (report && iReportAddedMembers)
+ {
+ AddIssue<EIssueIdentityField,EIssueTypeAddition>(¤t, currentfield,cfields[i].iLineNo,NULL,cfields[i]);
+ }
+ ++ret;
+ }
+ }
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// printlist
+// Output list members
+//
+// ----------------------------------------------------------------------------
+//
+void printlist(const NodeIndex::vtable_t& lista)
+{
+ NodeIndex::vtable_t::const_iterator it = lista.begin();
+ for (; it != lista.end(); ++it)
+ {
+ cout << it->first << endl;
+ }
+
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::indexVirtualMethods
+// ----------------------------------------------------------------------------
+//
+void ClassNodeAnalysis::indexVirtualMethods(HANodeIterator node,
+ const vector<DOMNode*>& virtualMethods,
+ const NodeIndex::vtable_t& vtable,
+ vector<pair<DOMNode*,int> >& virtualMethodsWithIndex)
+{
+ vector<DOMNode*>::const_iterator it = virtualMethods.begin();
+
+ for (; it != virtualMethods.end(); ++it)
+ {
+ NodeIndex::vtable_t::const_iterator vtableit = vtable.begin();
+ for (int i = 0; vtableit != vtable.end(); ++vtableit, ++i)
+ {
+ HANodeIterator funcnode(node);
+ funcnode.current = *it;
+
+ char index_str[256];
+
+ sprintf(index_str, "%d",i);
+
+ funcnode.SetAttribute(KXMLBBCVirtualFunctionIndex, index_str );
+
+ string funcsig = GenerateFunctionSignature(funcnode);
+ if (funcsig == vtableit->first)
+ {
+ virtualMethodsWithIndex.push_back(pair<DOMNode*,int>(*it,i));
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareVirtualTables
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareVirtualTables(HANodeIterator baseline,HANodeIterator current,
+ const NodeIndex::vtable_t& basevtable,
+ const NodeIndex::vtable_t& currentvtable,
+ bool report)
+{
+ if ( basevtable.size() != currentvtable.size() )
+ {
+ return 1;
+ }
+
+ NodeIndex::vtable_t::const_iterator baseit = basevtable.begin();
+ NodeIndex::vtable_t::const_iterator currentit = currentvtable.begin();
+
+ unsigned int i = 0;
+ for (i=0; baseit != basevtable.end(); ++baseit,++i,++currentit)
+ {
+
+ if ( baseit->first != currentit->first )
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareVirtualFunctions
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareVirtualFunctions(HANodeIterator baseline,HANodeIterator current,
+ const vector<DOMNode*>& bvirtualMethods,
+ const vector<DOMNode*>& cvirtualMethods,
+ bool report)
+{
+ int ret = 0;
+ //Analyse virtual methods, not a single change is tolerated
+
+ // First we build virtual tables for baseline and current classes.
+ const NodeIndex::vtable_t& basevtable = ClassGenerateVirtualTable(baseline);
+ const NodeIndex::vtable_t& currentvtable = ClassGenerateVirtualTable(current);
+
+ int parentLineNo = 0;
+ int lineNo = 0;
+ const XMLCh* parentlineNumber = current.GetAttribute(KXMLLineString);
+ parentLineNo = atoi(toString(parentlineNumber).c_str());
+
+ if ( 0 != compareVirtualTables(baseline,current,basevtable,currentvtable,report) )
+ {
+ // Virtual table has been changed.
+ AddIssue<EIssueIdentityVirtualTable,EIssueTypeChange>(&baseline, current, parentLineNo, NULL, "[Primary-vtable]");
+ }
+
+ vector<pair<DOMNode*,int> > bvirtualMethodsWithIndex;
+ vector<pair<DOMNode*,int> > cvirtualMethodsWithIndex;
+
+ // Add virtual methods to vectors with their indexes (i.e. order inside a class).
+ indexVirtualMethods(baseline,bvirtualMethods,basevtable,bvirtualMethodsWithIndex);
+ indexVirtualMethods(current,cvirtualMethods,currentvtable,cvirtualMethodsWithIndex);
+
+ unsigned int i = 0;
+ vector<bool> virtualMethodFound(cvirtualMethodsWithIndex.size(),false);
+
+ // Use only default comparator here, since virtual functions should have strict match.
+ const ComparatorVector& cmps = ComparatorFactory::Instance().GetComparators();
+ ComparatorVector::const_iterator defaultcomparator = cmps.begin();
+ assert( defaultcomparator != cmps.end() );
+
+ for (i=0; i < bvirtualMethodsWithIndex.size(); ++i)
+ {
+ HANodeIterator basemethod(baseline);
+ basemethod.current = bvirtualMethodsWithIndex[i].first;
+
+ unsigned int ii = 0;
+ for (ii=0; ii < cvirtualMethodsWithIndex.size(); ++ii)
+ {
+ HANodeIterator currentmethod(current);
+ currentmethod.current = cvirtualMethodsWithIndex[ii].first;
+
+ lineNo = 0;
+ const XMLCh* lineNumber = currentmethod.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+ if ( compareMethodsSignature(basemethod,currentmethod, **defaultcomparator) )
+ {
+ virtualMethodFound[ii] = true;
+ if (bvirtualMethodsWithIndex[i].second != cvirtualMethodsWithIndex[ii].second)
+ {
+ // Here the indexes don't match --> The order of virtual methods has been
+ // changed. This means that the layout of the virtual table has been changed
+ // and the binary compatibility is broken.
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeOrderChange>(&basemethod, currentmethod,lineNo);
+ }
+ ++ret;
+ }
+
+ //Check also the default parameter values
+ DOMElement * baselineelement = static_cast<DOMElement*>(basemethod.current);
+ DOMNodeList* baselinechilds = baselineelement->getChildNodes();
+ DOMElement * currentelement = static_cast<DOMElement*>(currentmethod.current);
+ DOMNodeList* currentchilds = currentelement->getChildNodes();
+
+ XMLSize_t childcount = baselinechilds->getLength();
+
+ unsigned int i = 0;
+ for (i = 0; i < childcount; ++i)
+ {
+ DOMNode* baselinechild = baselinechilds->item(i);
+ HANodeIterator baselinechildit(baseline);
+ baselinechildit.current = baselinechild;
+
+ DOMNode* currentchild = currentchilds->item(i);
+ HANodeIterator currentchildit(current);
+ currentchildit.current = currentchild;
+
+ short nodetype = baselinechildit->getNodeType();
+ if (nodetype == DOMNode::ELEMENT_NODE)
+ {
+ const XMLCh * baselinesize = FindAttributeValueForType(baselinechildit,KXMLSizeString);
+ const XMLCh * currentsize = FindAttributeValueForType(currentchildit,KXMLSizeString);
+
+ const XMLCh * baselinealign = FindAttributeValueForType(baselinechildit,KXMLAlignString);
+ const XMLCh * currentalign = FindAttributeValueForType(currentchildit,KXMLAlignString);
+
+ if ( !baselinesize )
+ {
+ baselinesize = baselinealign;
+ }
+
+ if ( !currentsize )
+ {
+ currentsize = currentalign;
+ }
+
+ if ( !Equals(baselinesize,currentsize) || !Equals(baselinealign, currentalign) ||
+ !CompareAttributes(baselinechildit,currentchildit,KXMLDefaultString,EOptionalSimpleAttribute))
+ {
+ ++ret;
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeParam>(&basemethod,currentmethod, lineNo);
+ }
+ break;
+ }
+ }
+ }
+ // check the return types of the methods
+ if ( !compareMethodsReturn(basemethod,currentmethod,**defaultcomparator) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeReturn>(&basemethod, currentmethod,lineNo);
+ }
+ ++ret;
+ }
+
+ if ( !CheckAccessModifier(basemethod,currentmethod) )
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeAccess>(&basemethod, currentmethod,lineNo);
+ }
+ ++ret;
+ }
+ break;
+ }
+ }
+
+ if ( cvirtualMethodsWithIndex.size() == ii )
+ {
+ //Method not found
+
+/*
+ // This code detects if the removed virtual function was actually an removed override.
+ unsigned int baseindex = bvirtualMethodsWithIndex[i].second;
+ HANodeIterator basemethod(baseline);
+ basemethod.current = bvirtualMethodsWithIndex[i].first;
+
+ if ( (baseindex < currentvtable.size()) && (currentvtable[baseindex].first == GenerateFunctionSignature(basemethod)) )
+ {
+ //This is a new override and we should report this if the class is derivable
+ if (ClassIsDerivable(baseline))
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeRemovedOverride>(&basemethod, basemethod);
+ }
+ ++ret;
+ }
+ }
+ else*/
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeRemoval>(&basemethod, basemethod,parentLineNo);
+ }
+ ++ret;
+ }
+ }
+ }
+
+ for (i = 0; i < virtualMethodFound.size(); ++i)
+ {
+ if (!virtualMethodFound[i])
+ {
+ HANodeIterator currentmethod(current);
+ currentmethod.current = cvirtualMethodsWithIndex[i].first;
+
+ lineNo = 0;
+ const XMLCh* lineNumber = currentmethod.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+ //Check the base vtable for entry for this function
+ unsigned int baseindex = cvirtualMethodsWithIndex[i].second;
+
+ if ( (baseindex < basevtable.size()) && (basevtable[baseindex].first == GenerateFunctionSignature(currentmethod)) )
+ {
+ //This is a new overwrite and we should report this if the class is derivable
+ if (ClassIsDerivable(baseline))
+ {
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeNewOverride>(¤tmethod, currentmethod,lineNo);
+ }
+ ++ret;
+ }
+ }
+ else
+ {
+ //This method really modifies the primary vtable
+ // If you also want to find out if this function overrides entry in vtable of non-primary base
+ // then generate virtual table for them and search for the function signature from them
+ if (report)
+ {
+ AddIssue<EIssueIdentityVirtualFunction,EIssueTypeAddition>(¤tmethod, currentmethod,lineNo);
+ }
+ ++ret;
+ }
+ }
+ }
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareBaseSizes
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareBaseSizes(HANodeIterator baseline, HANodeIterator current, const NodeIndex::dtable_t& bfields, const NodeIndex::dtable_t& cfields, bool report)
+{
+ int ret = 0;
+
+ if ( ClassIsDerivable(baseline) )
+ {
+ int bbasesize = ClassBaseSize(baseline,bfields);
+ int cbasesize = ClassBaseSize(current,cfields);
+
+ if ( (bbasesize) != (cbasesize) )
+ {
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+ ++ret;
+ if (report)
+ {
+ AddIssueClass<EIssueTypeBaseSize>(&baseline,iIdentity, current,lineNo);
+ }
+ }
+ }
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareClassMembers
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareClassMembers(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ int ret = 0;
+ //Base material
+ vector<DOMNode*> bvirtualMethods;
+ vector<DOMNode*> binlineMethods;
+ vector<DOMNode*> bexportedMethods;
+ vector<DOMNode*> bexportedvirtualMethods;
+ vector<DOMNode*> bmethods;
+ vector<DOMNode*> bfields;
+ vector<DOMNode*> bothers;
+
+ //Current material
+ vector<DOMNode*> cvirtualMethods;
+ vector<DOMNode*> cinlineMethods;
+ vector<DOMNode*> cexportedMethods;
+ vector<DOMNode*> cexportedvirtualMethods;
+ vector<DOMNode*> cmethods;
+ vector<DOMNode*> cfields;
+ vector<DOMNode*> cothers;
+
+ //Reserve some space for efficiency
+ bvirtualMethods.reserve(10);
+ bexportedMethods.reserve(10);
+ bmethods.reserve(10);
+ bfields.reserve(10);
+ bothers.reserve(10);
+
+ cvirtualMethods.reserve(10);
+ cexportedMethods.reserve(10);
+ cmethods.reserve(10);
+ cfields.reserve(10);
+ cothers.reserve(10);
+
+ //Order members
+ ClassOrderMembers(baseline,bvirtualMethods,binlineMethods,bexportedMethods,bexportedvirtualMethods,bmethods,bfields,bothers);
+ ClassOrderMembers(current,cvirtualMethods,cinlineMethods,cexportedMethods,cexportedvirtualMethods,cmethods,cfields,cothers);
+
+ //Virtual functions
+ ret += compareVirtualFunctions(baseline, current, bvirtualMethods, cvirtualMethods, report);
+
+ //if ( baseline.CheckForBooleanAttribute(KXMLBBCVirtualString) )
+ //{
+ //ret += compareExportedVirtualFunctions(baseline, current, bexportedvirtualMethods, cexportedvirtualMethods, report);
+ //}else if ( current.CheckForBooleanAttribute(KXMLBBCVirtualString) )
+ //{
+ //The class has changed from non-dynamic class to dynamic class
+ //Do we need to report something?
+ //}
+
+ //Exported methods
+ ret += compareNonvirtualFunctions(baseline,current,bexportedMethods,cexportedMethods,EIssueIdentityExportedFunction,report);
+
+ //Inlined methods
+ ret += compareNonvirtualFunctions(baseline, current, binlineMethods, cinlineMethods,EIssueIdentityInlineFunction, report);
+
+ //Fields
+ ret += compareFields(baseline,current,bfields, cfields, report);
+
+ //Others
+ ret += compareOthers(baseline, current, bothers, cothers, report);
+
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::compareBases
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::compareBases(HANodeIterator baseline,HANodeIterator current,bool report)
+{
+ //Check base classes
+ int ret = 0;
+
+ DOMNodeList* baselinechilds = baseline.GetElementsByTagName(KXMLBaseString);
+ DOMNodeList* currentchilds = current.GetElementsByTagName(KXMLBaseString);
+
+ XMLSize_t baselinechildcount = baselinechilds->getLength();
+ XMLSize_t currentchildcount = currentchilds->getLength();
+
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+ if ( baselinechildcount == currentchildcount )
+ {
+ unsigned int i = 0;
+ for (i = 0; i < baselinechildcount; ++i)
+ {
+ HANodeIterator baselineit(baseline);
+ HANodeIterator currentit(current);
+ baselineit.current = baselinechilds->item(i);
+
+ HANodeIterator basenameit(baseline);
+ basenameit.FindNodeById(baselineit.GetAttribute(KXMLTypeString));
+ string basename( GenerateFullyQualifiedName(basenameit) );
+
+ unsigned int ii = 0;
+ for (ii = 0; ii < currentchildcount; ++ii)
+ {
+ currentit.current = currentchilds->item(ii);
+
+ HANodeIterator currentnameit(current);
+ currentnameit.FindNodeById(currentit.GetAttribute(KXMLTypeString));
+ string currentname( GenerateFullyQualifiedName(currentnameit) );
+ if ( basename == currentname )
+ {
+ if ( basenameit.CheckForBooleanAttribute(KXMLBBCVirtualString) )
+ {
+
+ const NodeIndex::vtable_t& basevtable = ClassGenerateVirtualTable(basenameit);
+ const NodeIndex::vtable_t& currentvtable = ClassGenerateVirtualTable(currentnameit);
+
+ if ( 0 != compareVirtualTables(basenameit,currentnameit,basevtable,currentvtable,report) )
+ {
+ string vtablename = "[";
+ vtablename += basename;
+ vtablename += "-vtable]";
+ AddIssue<EIssueIdentityVirtualTable,EIssueTypeChange>(&baseline, current, lineNo, NULL, vtablename);
+ }
+
+ }
+ if (
+ !Equals( baselineit.GetAttribute(KXMLVirtualString), currentit.GetAttribute(KXMLVirtualString)) )
+ {
+ //Virtuality differs
+ if (report)
+ {
+ AddIssueClass<EIssueTypeInheritance>(&baseline,iIdentity, current,lineNo);
+ }
+ ++ret;
+ }
+
+ if ( !Equals( baselineit.GetAttribute(KXMLOffsetString), currentit.GetAttribute(KXMLOffsetString)) )
+ {
+ if (report)
+ {
+ string subobjectname = "[" + basename;
+ subobjectname += "]";
+ AddIssue<EIssueIdentitySubobject,EIssueTypeOffset>(&baseline,current,lineNo, NULL,subobjectname);
+ }
+ ++ret;
+ }
+ break;
+ }
+ }
+ if ( currentchildcount == ii )
+ {
+ if (report)
+ {
+ //AddIssueClass<EIssueTypeInheritance>(&baseline,iIdentity, current);
+ //base class removed from inheritance
+ string subobjectname = "[" + basename;
+ subobjectname += "]";
+ AddIssue<EIssueIdentitySubobject,EIssueTypeRemoval>(&baseline,current,lineNo, NULL,subobjectname);
+ }
+ ++ret;
+ }
+ }
+ } else
+ {
+ //Different amount of bases
+ if (report)
+ {
+ AddIssueClass<EIssueTypeInheritance>(&baseline,iIdentity, current,lineNo);
+ }
+ ++ret;
+
+ //check if a base class is removed from inheritance
+ unsigned int i = 0;
+ for (i = 0; i < baselinechildcount; ++i)
+ {
+ HANodeIterator baselineit(baseline);
+ HANodeIterator currentit(current);
+ baselineit.current = baselinechilds->item(i);
+
+ HANodeIterator basenameit(baseline);
+ basenameit.FindNodeById(baselineit.GetAttribute(KXMLTypeString));
+ string basename( GenerateFullyQualifiedName(basenameit) );
+
+ unsigned int ii = 0;
+ for (ii = 0; ii < currentchildcount; ++ii)
+ {
+ currentit.current = currentchilds->item(ii);
+
+ HANodeIterator currentnameit(current);
+ currentnameit.FindNodeById(currentit.GetAttribute(KXMLTypeString));
+
+ string currentname( GenerateFullyQualifiedName(currentnameit) );
+ if ( basename == currentname )
+ {
+ break;
+ }
+ }
+ if ( currentchildcount == ii )
+ {
+ if (report)
+ {
+ string subobjectname = "[" + basename;
+ subobjectname += "]";
+ AddIssue<EIssueIdentitySubobject,EIssueTypeRemoval>(&baseline,current,lineNo, NULL,subobjectname);
+ }
+ ++ret;
+ }
+ }
+ }
+
+ return ret;
+
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::ClassNodeAnalysis
+// ----------------------------------------------------------------------------
+//
+ClassNodeAnalysis::ClassNodeAnalysis()
+ : iReportAddedMembers(false),
+ iIdentity(EIssueIdentityClass)
+{
+}
+
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::Construct
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* ClassNodeAnalysis::Construct()
+{
+ return new ClassNodeAnalysis;
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::FindNodeAndAnalyse
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current)
+{
+ if ( baseline.CheckForBooleanAttribute(KXMIncompleteString) )
+ {
+ return 0;
+ }
+
+ DOMNode* node = NodeAnalysis::findNode(baseline,current);
+ if ( !node )
+ {
+ //AddIssue<>(&baseline,EIssue_class_removal);
+ AddIssue<EIssueIdentityClass,EIssueTypeRemoval>(&baseline, baseline,0);
+ return 1;
+ }
+ current.current = node;
+
+ return this->Analyse(baseline,current);
+}
+
+// ----------------------------------------------------------------------------
+// ClassNodeAnalysis::Analyse
+// ----------------------------------------------------------------------------
+//
+int ClassNodeAnalysis::Analyse(HANodeIterator baseline,HANodeIterator current, bool report)
+{
+ //ASSERTS
+ int ret=0;
+ short nodetype = baseline->getNodeType();
+ assert(nodetype == DOMNode::ELEMENT_NODE);
+ nodetype = current->getNodeType();
+ assert(nodetype == DOMNode::ELEMENT_NODE);
+ int lineNo = 0;
+ const XMLCh* lineNumber = current.GetAttribute(KXMLLineString);
+ lineNo = atoi(toString(lineNumber).c_str());
+
+ const XMLCh* baseanalysisstatus = baseline.GetAttribute(KXMLBBCAnalysisStatus);
+
+ if (baseanalysisstatus)
+ {
+ if ( Equals(baseanalysisstatus,KXMLBBCAnalysisStatusAnalysing) )
+ {
+ //We are analysing recursively, should not happen
+ assert(false);
+ }
+ else if ( Equals(baseanalysisstatus,KXMLBBCAnalysisStatusClean) )
+ {
+ return 0;
+ }
+
+ if (!report)
+ {
+ return 1;
+ }
+ }
+
+
+ baseline.SetAttribute(KXMLBBCAnalysisStatus,KXMLBBCAnalysisStatusAnalysing);
+
+ bool bincomplete = baseline.CheckForBooleanAttribute(KXMIncompleteString);
+ bool cincomplete = current.CheckForBooleanAttribute(KXMIncompleteString);
+
+ // Check if either baseline or current node is of incomplete type.
+ // Type is incomplete if the type is just forward declared or the
+ // analysed header file can be compiled without resolving the details
+ // of the type. This kind of situation occurs for example when only
+ // a reference or pointer to the class is used in the analyzed header,
+ // and the class is declared in other header file.
+ //
+ // If the type is incomplete, we cannot compare the nodes.
+ if ( bincomplete || cincomplete )
+ {
+ if ( bincomplete && cincomplete )
+ {
+ ret = 0;
+ }
+ else if (bincomplete)
+ {
+ ret = 0;
+ }
+ else
+ {
+ AddIssueClass<EIssueTypeNotAnalysed>(&baseline,iIdentity, baseline,0);
+ ret = 1;
+ }
+ }
+ else
+ {
+ // Check that the access level of the current node has not been changed
+ // to more restricted.
+ if (!CheckAccessModifier(baseline,current))
+ {
+ if (report)
+ {
+ AddIssueClass<EIssueTypeAccess>(&baseline,iIdentity, current,lineNo);
+ }
+ ret += 1;
+ }
+
+
+ // Check if the class has virtual bases
+ if ( baseline.CheckForBooleanAttribute(KXMLBBCVirtualInheritanceString) )
+ {
+ AddIssueClass<EIssueTypeVirtualBases>(&baseline,iIdentity, current,lineNo);
+ ++ret;
+ }
+
+ if ( current.CheckForBooleanAttribute(KXMLBBCVirtualInheritanceString) )
+ {
+ AddIssueClass<EIssueTypeVirtualBases>(¤t,iIdentity, current,lineNo);
+ ++ret;
+ }
+
+ // Check if the class is istantiable or derivable
+ if ( ClassIsInstantiable(baseline) || (ClassIsDerivable(baseline) && EIssueIdentityUnion != iIdentity) )
+ {
+
+ if ( !CompareAttributes(baseline,current,KXMLAlignString,ESimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssueClass<EIssueTypeAlign>(&baseline,iIdentity, current,lineNo);
+ iReportAddedMembers = true;
+ }
+ ret += 1;
+ }
+
+ if ( !CompareAttributes(baseline,current,KXMLSizeString,ESimpleAttribute) )
+ {
+ if (report)
+ {
+ AddIssueClass<EIssueTypeSize>(&baseline,iIdentity, current,lineNo);
+ iReportAddedMembers = true;
+ }
+ ret += 1;
+ }
+ }
+ //ret += compareBaseSizes(baseline,current,report);
+ ret += compareClassMembers(baseline,current,report);
+ ret += compareBases(baseline,current,report);
+ }
+
+ if ( ret == 0 )
+ {
+ baseline.SetAttribute(KXMLBBCAnalysisStatus,KXMLBBCAnalysisStatusClean);
+ } else
+ {
+ baseline.SetAttribute(KXMLBBCAnalysisStatus,KXMLBBCAnalysisStatusIssues);
+ }
+
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////StructNodeAnalysis///////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// StructNodeAnalysis::Construct
+// ----------------------------------------------------------------------------
+//
+NodeAnalysis* StructNodeAnalysis::Construct()
+{
+ return new StructNodeAnalysis;
+}
+
+// ----------------------------------------------------------------------------
+// StructNodeAnalysis::StructNodeAnalysis
+// ----------------------------------------------------------------------------
+//
+StructNodeAnalysis::StructNodeAnalysis()
+{
+ iIdentity = EIssueIdentityStruct;
+}
+////////////////////////////////////////////////////////////////////////////////////////
+