blob: cce0121124d74401dbaf0ed1bc230bc7bde6d9bb [file]
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
from analysis.occurrence import RankByOccurrence
from analysis.project import Project
from analysis.type_enums import LanguageType
class ProjectClassifier(object):
"""Determines the project of a crash - (project_name, project_path).
For example: ('chromium', 'src'), ('skia', 'src/skia'), ...etc.
"""
def __init__(self, projects, top_n_frames,
non_chromium_project_rank_priority=None):
super(ProjectClassifier, self).__init__()
self.projects = projects
self.top_n_frames = top_n_frames
self.non_chromium_project_rank_priority = non_chromium_project_rank_priority
@staticmethod
def _GetTopProject(projects, rank_function=None):
"""Gets the highest ranking class among projects."""
projects = RankByOccurrence(projects, 1, rank_function=rank_function)
if projects:
return projects[0]
logging.warning('ProjectClassifier.Classify: no projects found.')
return None
def ClassifyCallStack(self, crash_stack):
"""Determines which project is responsible for this crash stack.
Args:
crash_stack (CallStack): The crash_stack of the Stacktrace for this crash.
Returns:
The name of the most-suspected project; or the empty string on failure.
"""
rank_function = None
if crash_stack.language_type == LanguageType.JAVA:
def RankFunctionForJava(occurrence):
if 'chromium' in occurrence.name:
index = 0
else:
index = self.non_chromium_project_rank_priority[occurrence.name]
return -len(occurrence), index
rank_function = RankFunctionForJava
def GetProjectFromStackFrame(frame):
"""Determine which project is responsible for this frame."""
for project in self.projects:
if project.MatchesStackFrame(frame):
return project.GetName(frame.dep_path)
return None
projects = map(GetProjectFromStackFrame,
crash_stack.frames[:self.top_n_frames])
return ProjectClassifier._GetTopProject(projects,
rank_function=rank_function)
def ClassifyDepPath(self, dep_path):
"""Determine which project is responsible for this dep_path."""
for project in self.projects:
if project.MatchesDepPath(dep_path):
return project.GetName(dep_path)
return ''
def ClassifySuspect(self, suspect):
"""Determine which project is responsible for this suspect."""
if not suspect or not suspect.changelog:
return None
def GetProjectFromTouchedFile(touched_file):
for project in self.projects:
if project.MatchesTouchedFile(suspect.dep_path,
touched_file.changed_path):
return project.GetName(suspect.dep_path)
return None
projects = map(GetProjectFromTouchedFile, suspect.changelog.touched_files)
return ProjectClassifier._GetTopProject(projects,
rank_function=lambda x:-len(x))
def ClassifySuspects(self, suspects):
"""Determines which project is resposible for these suspects.
Args:
suspects (list of Suspect): culprit suspects.
Returns:
The name of the most-suspected project; or the empty string on failure.
"""
projects = map(self.ClassifySuspect, suspects)
return ProjectClassifier._GetTopProject(projects,
rank_function=lambda x:-len(x))