diff -r 000000000000 -r 638b9c697799 apicompatanamdw/compatanalysercmd/headeranalyser/src/BBCAnalyser.cpp --- /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 +#include +#include +#include +#include +#include + +#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 > 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 > 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 > 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 BBCAnalyser::checkForEmptyFiles(HANodeIterator rootnode, const list& filesToAnalyse, const list& aMacroFiles) +{ + DOMNodeList* childs = rootnode.GetElementsByTagName(KXMLFileString); + XMLSize_t childcount = childs->getLength(); + + vector 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::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::const_iterator start = filesToAnalyse.begin(); + for(unsigned int i=0; i < filesToAnalyse.size(); i++, start++) + { + if(!filefound[i]) + { + list::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 & 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::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 >& 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 >& filesToAnalyse, const list& 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 basefiles, currentfiles; + list< pair >::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 bfilefound; + bfilefound = checkForEmptyFiles(baselineit,basefiles,aMacroFiles); + + vector cfilefound; + cfilefound = checkForEmptyFiles(currentit,currentfiles,aMacroFiles); + + list >::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(true), SCseverityAccessible(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(true), SCseverityAccessible(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(true), SCseverityAccessible(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 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(&baseline, baseline,0); + } + return 1; +} + + +// ---------------------------------------------------------------------------- +// UnderConstructionNodeAnalysis::FindNodeAndAnalyse +// +// ---------------------------------------------------------------------------- +// +int UnderConstructionNodeAnalysis::FindNodeAndAnalyse(HANodeIterator baseline,HANodeIterator current) +{ + AddIssue(&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(&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(&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(&baseline, current,lineNo); + } + ++ret; + } + delete analyser; + } + } + else + { + //{KXMLTypeString,EIdAttribute} + if ( !CompareAttributes(baseline,current,KXMLTypeString,ETypeAttribute) ) + { + if (report) + { + AddIssue(&baseline, current,lineNo); + } + ++ret; + } + } + + //{KXMLInitString,EOptionalSimpleAttribute} + if ( !CompareAttributes(baseline,current,KXMLInitString,EOptionalSimpleAttribute) ) + { + if (report) + { + AddIssue(&baseline, current,lineNo); + } + ++ret; + } + + if (!CheckAccessModifier(baseline,current)) + { + if (report) + { + //AddIssue(&baseline, current); + AddIssue(&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(&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(&enumchildit, current, lineNo, baseline.GetAttribute(KXMLFileIdString)); + ++ret; + } + HANodeIterator currentparent(current); + if ( FindParentContext(current, currentparent)) + { + if ( !CheckAccessModifier(baseline,currentparent) ) + { + AddIssue(&enumchildit, current, lineNo, baseline.GetAttribute(KXMLFileIdString)); + ++ret; + } + } + } + } + else + { + + DOMNode* node = NodeAnalysis::findNode(baseline,current); + if ( !node ) + { + AddIssue(&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(&baseline, current,lineNo); + } + ++ret; + } + + //{KXMLSizeString,ESimpleAttribute} + if ( !CompareAttributes(baseline,current,KXMLSizeString,ESimpleAttribute) ) + { + if (report) + { + AddIssue(&baseline, current,lineNo); + } + ++ret; + } + + if (!CheckAccessModifier(baseline,current)) + { + if (report) + { + //AddIssue(&baseline, current); + AddIssue(&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(&baseline, current,lineNo); + } + ++ret; + return ret; + } + break; + } + + } + + if ( currentchildcount == ii ) + { + + if (report) + { + AddIssue(&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(&baseline, baseline); + AddIssueFunction(&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; +// +// +// +// + + 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(&baseline,iFuncType,baseline,0); + + } + ++ret; + return ret; + } + + string basefuncsig = GenerateFunctionSignature(baseline); + string currentfuncsig = GenerateFunctionSignature(current); + + if ( basefuncsig != currentfuncsig ) + { + ++ret; + if (report) + { + AddIssueFunction(&baseline,iFuncType,current,lineNo); + } + } + else + { + //Check also the default parameter values + DOMElement * baselineelement = static_cast(baseline.current); + DOMNodeList* baselinechilds = baselineelement->getChildNodes(); + DOMElement * currentelement = static_cast(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(&baseline, current); + AddIssueFunction(&baseline,iFuncType,current,lineNo); + } + break; + } + } + + } + + } + + if ( !CompareAttributes(baseline,current,KXMLReturnsString,EOptionalTypeAttribute) ) + { + ++ret; + if (report) + { + AddIssueFunction(&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(&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()) + ); + + // + + 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(&baseline, current,lineNo); + } + ++ret; + } + + if ( !CompareAttributes(baseline,current,KXMLTypeString,ETypeAttribute) ) + { + if (report) + { + AddIssue(&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(&baseline, current,lineNo); + } + ++ret; + } + } + + if (!CheckAccessModifier(baseline,current)) + { + if (report) + { + //AddIssue(&baseline, current); + AddIssue(&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(&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& bvirtualMethods, + const vector& 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(basemethod.current); + DOMElement * currnodeelement = static_cast(currentmethod.current); + std::vector baseElementNodes; + std::vector 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) +{ + // + // + // + // + 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(&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(&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(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember); + } + ++ret; + } + delete analyser; + } + } + else + { + //{KXMLTypeString,EIdAttribute} + if ( !CompareAttributes(basefield,currentfield,KXMLTypeString,ETypeAttribute) ) + { + ret++; + if ( report ) + { + AddIssueField(&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(&baseline,identity, currentfield,currentmember.iLineNo,NULL,basemember); + } + else + { + return ret; + } + } + + } + } + return ret; +} + +// ---------------------------------------------------------------------------- +// dumpNodeVectordumpNodeVector +// ---------------------------------------------------------------------------- +// +void dumpNodeVector(HANodeIterator node,const vector & nodes) +{ + DEBUG_PRINT("Dumping node vector:\n") + vector::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& bexportedMethods, + const vector& 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::const_iterator i = bexportedMethods.begin(); + for( ; i != bexportedMethods.end(); ++i ) + { + baseMap.insert( make_pair(*i, MethodMatchFlags(false, false))); + } + + vector::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(&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(&removedMethod,identity, removedMethod,lineNo); + ++ret; + } + } + } + return ret; +} +// ---------------------------------------------------------------------------- +// ClassNodeAnalysis::compareNonvirtualFunctions +// ---------------------------------------------------------------------------- +// +int ClassNodeAnalysis::compareNonvirtualFunctions( + HANodeIterator baseline, + HANodeIterator current, + const vector& bexportedMethods, + const vector& 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::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::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(&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(&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(basemethod.current); + DOMNodeList* baselinechilds = baselineelement->getChildNodes(); + DOMElement * currentelement = static_cast(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(&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(&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(&basemethod,identity,currentmethod,lineNo1); + } + } + + baseMapIter->second.returnValueMatch = true; + currMapIter->second.returnValueMatch = true; + break; + } + retComparatorRound++; + } + + + if ( !CheckAccessModifier(basemethod,currentmethod) ) + { + if (report) + { + AddIssueFunction(&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& bothers, const vector& 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& bfields_class, + const vector& 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 fieldFound(cfields.size(),false); + vector fieldRemoved(bfields.size(),false); + vector fieldChanged(bfields.size(),false); + vector fieldChangedCurrent(bfields.size(),-1); + vector 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(&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(&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(&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(&baseline, basefield,lineNo,NULL,bfields[i]); + } + else + { + AddIssue(&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(&baseline,current,lineNo,NULL,cfields[i]); + } + continue; + } + + HANodeIterator currentfield(current); + currentfield.current = cfields[i].iNode; + if (report && iReportAddedMembers) + { + AddIssue(¤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& virtualMethods, + const NodeIndex::vtable_t& vtable, + vector >& virtualMethodsWithIndex) +{ + vector::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(*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& bvirtualMethods, + const vector& 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(&baseline, current, parentLineNo, NULL, "[Primary-vtable]"); + } + + vector > bvirtualMethodsWithIndex; + vector > 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 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(&basemethod, currentmethod,lineNo); + } + ++ret; + } + + //Check also the default parameter values + DOMElement * baselineelement = static_cast(basemethod.current); + DOMNodeList* baselinechilds = baselineelement->getChildNodes(); + DOMElement * currentelement = static_cast(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(&basemethod,currentmethod, lineNo); + } + break; + } + } + } + // check the return types of the methods + if ( !compareMethodsReturn(basemethod,currentmethod,**defaultcomparator) ) + { + if (report) + { + AddIssue(&basemethod, currentmethod,lineNo); + } + ++ret; + } + + if ( !CheckAccessModifier(basemethod,currentmethod) ) + { + if (report) + { + AddIssue(&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(&basemethod, basemethod); + } + ++ret; + } + } + else*/ + { + if (report) + { + AddIssue(&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(¤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(¤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(&baseline,iIdentity, current,lineNo); + } + } + } + return ret; +} + +// ---------------------------------------------------------------------------- +// ClassNodeAnalysis::compareClassMembers +// ---------------------------------------------------------------------------- +// +int ClassNodeAnalysis::compareClassMembers(HANodeIterator baseline,HANodeIterator current, bool report) +{ + int ret = 0; + //Base material + vector bvirtualMethods; + vector binlineMethods; + vector bexportedMethods; + vector bexportedvirtualMethods; + vector bmethods; + vector bfields; + vector bothers; + + //Current material + vector cvirtualMethods; + vector cinlineMethods; + vector cexportedMethods; + vector cexportedvirtualMethods; + vector cmethods; + vector cfields; + vector 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(&baseline, current, lineNo, NULL, vtablename); + } + + } + if ( + !Equals( baselineit.GetAttribute(KXMLVirtualString), currentit.GetAttribute(KXMLVirtualString)) ) + { + //Virtuality differs + if (report) + { + AddIssueClass(&baseline,iIdentity, current,lineNo); + } + ++ret; + } + + if ( !Equals( baselineit.GetAttribute(KXMLOffsetString), currentit.GetAttribute(KXMLOffsetString)) ) + { + if (report) + { + string subobjectname = "[" + basename; + subobjectname += "]"; + AddIssue(&baseline,current,lineNo, NULL,subobjectname); + } + ++ret; + } + break; + } + } + if ( currentchildcount == ii ) + { + if (report) + { + //AddIssueClass(&baseline,iIdentity, current); + //base class removed from inheritance + string subobjectname = "[" + basename; + subobjectname += "]"; + AddIssue(&baseline,current,lineNo, NULL,subobjectname); + } + ++ret; + } + } + } else + { + //Different amount of bases + if (report) + { + AddIssueClass(&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(&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(&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(&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(&baseline,iIdentity, current,lineNo); + } + ret += 1; + } + + + // Check if the class has virtual bases + if ( baseline.CheckForBooleanAttribute(KXMLBBCVirtualInheritanceString) ) + { + AddIssueClass(&baseline,iIdentity, current,lineNo); + ++ret; + } + + if ( current.CheckForBooleanAttribute(KXMLBBCVirtualInheritanceString) ) + { + AddIssueClass(¤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(&baseline,iIdentity, current,lineNo); + iReportAddedMembers = true; + } + ret += 1; + } + + if ( !CompareAttributes(baseline,current,KXMLSizeString,ESimpleAttribute) ) + { + if (report) + { + AddIssueClass(&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; +} +//////////////////////////////////////////////////////////////////////////////////////// +