File indexing completed on 2024-04-14 14:56:24

0001 # -*- coding: utf-8 -*-
0002 #     Copyright 2009 Simon Edwards <simon@simonzone.com>
0003 #
0004 # This program is free software; you can redistribute it and/or modify
0005 # it under the terms of the GNU General Public License as published by
0006 # the Free Software Foundation; either version 2 of the License, or
0007 # (at your option) any later version.
0008 #
0009 # This program is distributed in the hope that it will be useful,
0010 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012 # GNU General Public License for more details.
0013 #
0014 # You should have received a copy of the GNU General Public License
0015 # along with this program; if not, write to the
0016 # Free Software Foundation, Inc.,
0017 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 
0019 def MergeSipScope(sipsym,primaryScope,updateScope):
0020     """
0021     Updates the given primary scope using the content of the update scope.
0022     The primary scope typically contains extra annotations and edits which
0023     have been added by hand. This function updates the primary scope with
0024     function, class and method etc contents of the update scope while
0025     trying to preserve any manually added annoations etc.
0026     
0027     Keyword arguments:
0028     primaryScope -- A `sipsymboldata.SymbolData.Scope`
0029     updateScope -- A `sipsymboldata.SymbolData.Scope` object. Update information is taken from here and merged into the primary scope.
0030     """
0031     newScope = primaryScope
0032     oldScope = updateScope
0033     primaryFunctionMap = {}
0034     primaryClassMap = {}
0035     primaryNamespaceMap = {}
0036     primaryEnumMap = {}
0037     primaryTypedefMap = {}
0038     
0039     handledFunctions = set()
0040     
0041     # Index the primary scope
0042     for item in primaryScope:
0043         if isinstance(item,sipsym.Function) or isinstance(item,sipsym.Constructor) or isinstance(item,sipsym.Destructor):
0044             primaryFunctionMap[_MangleFunctionName(sipsym,item)] = item
0045         elif isinstance(item,sipsym.SipClass):
0046             primaryClassMap[item.fqName()] = item
0047         elif isinstance(item,sipsym.Namespace):
0048             primaryNamespaceMap[item.fqName()] = item
0049         elif isinstance(item,sipsym.Enum):    
0050             primaryEnumMap[item.fqName()] = item
0051         elif isinstance(item,sipsym.Typedef):
0052             primaryTypedefMap[item.fqName()] = item
0053 
0054     # Update
0055     for item in updateScope[:]:
0056         # Loop over a copy of the item because we might change the list on the fly.
0057         
0058         if isinstance(item,sipsym.Function) or isinstance(item,sipsym.Constructor) or isinstance(item,sipsym.Destructor):
0059             mangledName = _MangleFunctionName(sipsym,item)
0060             if mangledName in primaryFunctionMap:
0061                 _MergeSipFunction(sipsym,primaryFunctionMap[mangledName],item)
0062                 del primaryFunctionMap[mangledName]
0063                 handledFunctions.add(mangledName)
0064             else:
0065                 # New function.
0066                 if mangledName not in handledFunctions:
0067                     primaryScope.append(item)
0068                 
0069         elif isinstance(item,sipsym.SipClass):
0070             if item.fqName() in primaryClassMap:
0071                 _MergeSipClass(sipsym,primaryClassMap[item.fqName()],item)
0072             else:
0073                 # New class
0074                 primaryScope.append(item)
0075                 
0076         elif isinstance(item,sipsym.Namespace):
0077             if item.fqName() in primaryNamespaceMap:
0078                 primaryNamespace = primaryNamespaceMap[item.fqName()]
0079                 if not primaryNamespace.ignore():
0080                     MergeSipScope(sipsym,primaryNamespace,item)
0081             else:
0082                 # New namespace
0083                 primaryScope.append(item)
0084                 
0085         elif isinstance(item,sipsym.Enum):
0086             if item.fqName() in primaryEnumMap:
0087                 _MergeEnum(sipsym,primaryEnumMap[item.fqName()],item)
0088                 del primaryEnumMap[item.fqName()]
0089             else:
0090                 # New enum
0091                 primaryScope.append(item)
0092         
0093         elif isinstance(item,sipsym.Typedef):
0094             # FIXME Try to be independant from Qt not hard code QFlags in.
0095             if item.argumentType() is not None and "QFlags" in item.argumentType():
0096                 if item.fqName() not in primaryTypedefMap:
0097                     primaryScope.append(item)
0098             else:
0099                 print("Warning: Skipping typdef " +str(item))
0100         else:
0101             if not isinstance(item,sipsym.SipDirective) and not isinstance(item,sipsym.Comment):
0102                 print("Warning: Unknown object " +str(item))
0103                 
0104     # Handle any left over functions which are forced.
0105     for primaryFunctionName,function in primaryFunctionMap.items():
0106         if not function.force():
0107             del primaryScope[primaryScope.index(function)]
0108 
0109     for primaryEnumName,enum in primaryEnumMap.items():
0110         if not enum.force():
0111             del primaryScope[primaryScope.index(enum)]
0112             
0113     primaryScope._fixScope()
0114 
0115 def _MergeSipFunction(sipsym,primaryFunction,updateFunction):
0116     if updateFunction.annotations() is not None:
0117         annotations = set(updateFunction.annotations())
0118         if primaryFunction.annotations() is not None:
0119             annotations.update(primaryFunction.annotations())
0120         primaryFunction.setAnnotations(annotations)
0121 
0122     # Update the arguments by name.
0123     
0124     def name(item):
0125         if item.name() is not None and name!="": 
0126             return item.name()
0127         else:
0128             return "$a" + str(i)
0129     
0130     primaryArguments = {}
0131     i = 0
0132     for arg in primaryFunction.arguments():
0133         primaryArguments[name(arg)] = arg
0134         i += 1
0135         
0136     newArguments = []
0137     i = 0
0138     for updateArg in updateFunction.arguments():
0139         if name(updateArg) in primaryArguments:
0140             newArguments.append(_MergeArgument(sipsym,primaryArguments[name(updateArg)],updateArg))
0141         else:
0142             newArguments.append(_MergeArgument(sipsym,updateArg,updateArg))
0143         i += 1
0144             
0145     primaryFunction.setArguments(newArguments)
0146 
0147 def _MangleFunctionName(sipsym,function):
0148     name = function.name()
0149     if isinstance(function,sipsym.Destructor):
0150         name = "~" + name
0151 
0152     name = name + '(' + \
0153         ','.join([arg.argumentType() for arg in function.arguments() if arg.defaultValue() is None]) + ')'
0154 
0155     if 'const' in function._qualifier:
0156         name = name + " const"
0157         
0158     return name
0159 
0160 def _MergeArgument(sipsym,primaryArgument,updateArgument):
0161     resultArg = sipsym.Argument(primaryArgument.argumentType(),
0162                     primaryArgument.name(),
0163                     primaryArgument.defaultValue(),
0164                     primaryArgument.template(),
0165                     primaryArgument.defaultTypes())
0166     
0167     annotations = list(primaryArgument.annotations())
0168     for anno in updateArgument.annotations():
0169         if anno not in annotations:
0170             annotations.append(anno)
0171 
0172     resultArg.setAnnotations(annotations)
0173     return resultArg
0174 
0175 def _MergeSipClass(sipsym,primaryClass,updateClass):
0176     annotations = list(updateClass.annotations())
0177     for anno in primaryClass.annotations():
0178         if anno not in annotations:
0179             annotations.append(anno)
0180     primaryClass.setAnnotations(annotations)
0181     
0182     MergeSipScope(sipsym,primaryClass,updateClass)
0183     
0184 def _MergeEnum(sipsym,primaryEnum,updateEnum):
0185     annotations = list(updateEnum.annotations())
0186     for anno in primaryEnum.annotations():
0187         if anno not in annotations:
0188             annotations.append(anno)
0189     primaryEnum.setAnnotations(annotations)
0190 
0191     primaryEnum[:] = [sipsym.Enumerator(e.name(),e.value()) for e in updateEnum]