| # |
| # Copyright (C) 2016 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| |
| class ArcSummary(object): |
| """Summarizes an arc from a .gcno file. |
| |
| Attributes: |
| src_block_index: integer index of the source basic block. |
| dstBlockIndex: integer index of the destination basic block. |
| on_tree: True iff arc has flag GCOV_ARC_ON_TREE. |
| fake: True iff arc has flag GCOV_ARC_FAKE. |
| fallthrough: True iff arc has flag GCOV_ARC_FALLTHROUGH. |
| resolved: True iff the arc's count has been resolved. |
| count: Integer number of times the arc was covered. |
| """ |
| |
| GCOV_ARC_ON_TREE = 1 |
| GCOV_ARC_FAKE = 1 << 1 |
| GCOV_ARC_FALLTHROUGH = 1 << 2 |
| |
| def __init__(self, src_block, dst_block, flag): |
| """Inits the arc summary with provided values. |
| |
| Stores the source and destination block indices and parses |
| the arc flag. |
| |
| Args: |
| src_block: BlockSummary of source block. |
| dst_block: BlockSummary of destination block. |
| flag: integer flag for the given arc. |
| """ |
| |
| self.src_block = src_block |
| self.dst_block = dst_block |
| self.on_tree = bool(flag & self.GCOV_ARC_ON_TREE) |
| self.fake = bool(flag & self.GCOV_ARC_FAKE) |
| self.fallthrough = bool(flag & self.GCOV_ARC_FALLTHROUGH) |
| self.resolved = False |
| self.count = 0 |
| |
| def Resolve(self): |
| """Resolves the arc count and returns True if successful. |
| |
| Uses the property that the sum of counts of arcs entering a |
| node is equal to the sum of counts of arcs leaving a node. The |
| exception to this rule is fake non-fallthrough nodes, which have |
| no exit edges. In this case, remove the arc as an exit arc from |
| the source so that the source can be resolved. |
| |
| Returns: |
| True if the arc could be resolved and False otherwise. |
| """ |
| if self.fake and not self.fallthrough: |
| try: |
| self.src_block.exit_arcs.remove(self) |
| except ValueError: |
| pass |
| elif (len(self.src_block.entry_arcs) > 0 and |
| all(a.resolved for a in self.src_block.entry_arcs) and |
| all(a.resolved for a in self.src_block.exit_arcs if a != self)): |
| in_flow = sum(a.count for a in self.src_block.entry_arcs) |
| out_flow = sum(a.count for a in self.src_block.exit_arcs |
| if a != self) |
| self.count = in_flow - out_flow |
| self.resolved = True |
| elif (len(self.dst_block.exit_arcs) > 0 and |
| all(a.resolved for a in self.dst_block.exit_arcs) and |
| all(a.resolved for a in self.dst_block.entry_arcs if a != self)): |
| out_flow = sum(a.count for a in self.dst_block.exit_arcs) |
| in_flow = sum(a.count for a in self.dst_block.entry_arcs |
| if a != self) |
| self.count = out_flow - in_flow |
| self.resolved = True |
| else: |
| return False |
| return True |