/// <summary> /// Returns the data flow map for the given control flow graph. /// </summary> /// <param name="summary">MethodSummary</param> /// <param name="context">AnalysisContext</param> /// <returns>DataFlowMap</returns> internal static DataFlowMap AnalyseControlFlowGraph(MethodSummary summary, AnalysisContext context) { var dataFlowMap = new DataFlowMap(); var model = context.Compilation.GetSemanticModel(summary.Method.SyntaxTree); foreach (var param in summary.Method.ParameterList.Parameters) { var declType = model.GetTypeInfo(param.Type).Type; if (context.IsTypeAllowedToBeSend(declType) || context.IsMachineType(declType, model)) { continue; } var paramSymbol = model.GetDeclaredSymbol(param); dataFlowMap.MapRefToSymbol(paramSymbol, paramSymbol, summary.Method.ParameterList, summary.Node, false); } DataFlowAnalysis.AnalyseControlFlowGraphNode(summary.Node, summary.Node, summary.Method.ParameterList, dataFlowMap, model, context); return dataFlowMap; }
/// <summary> /// Performs data flow analysis on the given control flow graph node. /// </summary> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="previousCfgNode">Previous controlFlowGraphNode</param> /// <param name="previousSyntaxNode">Previous syntaxNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> private static void AnalyseControlFlowGraphNode(ControlFlowGraphNode cfgNode, ControlFlowGraphNode previousCfgNode, SyntaxNode previousSyntaxNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!cfgNode.IsJumpNode && !cfgNode.IsLoopHeadNode) { foreach (var syntaxNode in cfgNode.SyntaxNodes) { dataFlowMap.Transfer(previousSyntaxNode, previousCfgNode, syntaxNode, cfgNode); var stmt = syntaxNode as StatementSyntax; var localDecl = stmt.DescendantNodesAndSelf().OfType<LocalDeclarationStatementSyntax>().FirstOrDefault(); var expr = stmt.DescendantNodesAndSelf().OfType<ExpressionStatementSyntax>().FirstOrDefault(); var ret = stmt.DescendantNodesAndSelf().OfType<ReturnStatementSyntax>().FirstOrDefault(); if (localDecl != null) { var varDecl = (stmt as LocalDeclarationStatementSyntax).Declaration; foreach (var variable in varDecl.Variables) { if (variable.Initializer == null) { continue; } DataFlowAnalysis.TryCaptureParameterAccess(variable.Initializer.Value, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(variable.Initializer.Value, syntaxNode, cfgNode, dataFlowMap, model, context); ITypeSymbol declType = null; if (variable.Initializer.Value is LiteralExpressionSyntax && variable.Initializer.Value.IsKind(SyntaxKind.NullLiteralExpression)) { declType = model.GetTypeInfo(varDecl.Type).Type; } else { declType = model.GetTypeInfo(variable.Initializer.Value).Type; } if (context.IsTypeAllowedToBeSend(declType) || context.IsMachineType(declType, model)) { continue; } var declSymbol = model.GetDeclaredSymbol(variable); if (variable.Initializer.Value is IdentifierNameSyntax || variable.Initializer.Value is MemberAccessExpressionSyntax) { ISymbol varSymbol = null; if (variable.Initializer.Value is IdentifierNameSyntax) { varSymbol = model.GetSymbolInfo(variable.Initializer.Value as IdentifierNameSyntax).Symbol; } else if (variable.Initializer.Value is MemberAccessExpressionSyntax) { varSymbol = model.GetSymbolInfo((variable.Initializer.Value as MemberAccessExpressionSyntax).Name).Symbol; } dataFlowMap.MapRefToSymbol(varSymbol, declSymbol, syntaxNode, cfgNode); HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, varSymbol, syntaxNode, cfgNode, dataFlowMap)) { dataFlowMap.MapObjectTypesToSymbol(objectTypes, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } else if (variable.Initializer.Value is LiteralExpressionSyntax && variable.Initializer.Value.IsKind(SyntaxKind.NullLiteralExpression)) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (variable.Initializer.Value is InvocationExpressionSyntax) { var invocation = variable.Initializer.Value as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (returnSymbols.Contains(declSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode, false); } else { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode); } if (reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, declSymbol, syntaxNode, cfgNode); } if (summary != null && summary.ReturnTypeSet.Count > 0) { dataFlowMap.MapObjectTypesToSymbol(summary.ReturnTypeSet, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } else if (variable.Initializer.Value is ObjectCreationExpressionSyntax) { var objCreation = variable.Initializer.Value as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (returnSymbols.Contains(declSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode, false); } else { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode); } if (reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, declSymbol, syntaxNode, cfgNode); } var typeSymbol = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (typeSymbol != null) { dataFlowMap.MapObjectTypesToSymbol(new HashSet<ITypeSymbol> { typeSymbol }, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } } } else if (expr != null) { if (expr.Expression is BinaryExpressionSyntax) { var binaryExpr = expr.Expression as BinaryExpressionSyntax; DataFlowAnalysis.TryCaptureParameterAccess(binaryExpr.Left, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureParameterAccess(binaryExpr.Right, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(binaryExpr.Left, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(binaryExpr.Right, syntaxNode, cfgNode, dataFlowMap, model, context); IdentifierNameSyntax lhs = null; ISymbol lhsFieldSymbol = null; if (binaryExpr.Left is IdentifierNameSyntax) { lhs = binaryExpr.Left as IdentifierNameSyntax; var lhsType = model.GetTypeInfo(lhs).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } } else if (binaryExpr.Left is MemberAccessExpressionSyntax) { var name = (binaryExpr.Left as MemberAccessExpressionSyntax).Name; var lhsType = model.GetTypeInfo(name).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } lhs = context.GetFirstNonMachineIdentifier(binaryExpr.Left, model); lhsFieldSymbol = model.GetSymbolInfo(name as IdentifierNameSyntax).Symbol; } else if (binaryExpr.Left is ElementAccessExpressionSyntax) { var memberAccess = (binaryExpr.Left as ElementAccessExpressionSyntax); if (memberAccess.Expression is IdentifierNameSyntax) { lhs = memberAccess.Expression as IdentifierNameSyntax; var lhsType = model.GetTypeInfo(lhs).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } } else if (memberAccess.Expression is MemberAccessExpressionSyntax) { var name = (memberAccess.Expression as MemberAccessExpressionSyntax).Name; var lhsType = model.GetTypeInfo(name).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } lhs = context.GetFirstNonMachineIdentifier(memberAccess.Expression, model); lhsFieldSymbol = model.GetSymbolInfo(name as IdentifierNameSyntax).Symbol; } } var leftSymbol = model.GetSymbolInfo(lhs).Symbol; if (binaryExpr.Right is IdentifierNameSyntax || binaryExpr.Right is MemberAccessExpressionSyntax) { IdentifierNameSyntax rhs = null; if (binaryExpr.Right is IdentifierNameSyntax) { rhs = binaryExpr.Right as IdentifierNameSyntax; } else if (binaryExpr.Right is MemberAccessExpressionSyntax) { rhs = context.GetFirstNonMachineIdentifier(binaryExpr.Right, model); } var rightSymbol = model.GetSymbolInfo(rhs).Symbol; dataFlowMap.MapRefToSymbol(rightSymbol, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefToSymbol(rightSymbol, lhsFieldSymbol, syntaxNode, cfgNode); } HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, rightSymbol, syntaxNode, cfgNode, dataFlowMap)) { dataFlowMap.MapObjectTypesToSymbol(objectTypes, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is LiteralExpressionSyntax && binaryExpr.Right.IsKind(SyntaxKind.NullLiteralExpression)) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is InvocationExpressionSyntax) { var invocation = binaryExpr.Right as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); DataFlowAnalysis.CheckForNonMappedFieldSymbol(invocation, cfgNode, dataFlowMap, model, context); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (returnSymbols.Contains(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode, false); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode, false); } } else { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } } if (lhsFieldSymbol != null && reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } if (summary != null && summary.ReturnTypeSet.Count > 0) { dataFlowMap.MapObjectTypesToSymbol(summary.ReturnTypeSet, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is ObjectCreationExpressionSyntax) { var objCreation = binaryExpr.Right as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (returnSymbols.Contains(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode, false); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode, false); } } else { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } } if (lhsFieldSymbol != null && reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } var typeSymbol = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (typeSymbol != null) { dataFlowMap.MapObjectTypesToSymbol(new HashSet<ITypeSymbol> { typeSymbol }, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } } else if (expr.Expression is InvocationExpressionSyntax) { var invocation = expr.Expression as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); DataFlowAnalysis.CheckForNonMappedFieldSymbol(invocation, cfgNode, dataFlowMap, model, context); } } else if (ret != null) { HashSet<ISymbol> returnSymbols = null; if (ret.Expression is IdentifierNameSyntax || ret.Expression is MemberAccessExpressionSyntax) { IdentifierNameSyntax rhs = null; if (ret.Expression is IdentifierNameSyntax) { rhs = ret.Expression as IdentifierNameSyntax; } else if (ret.Expression is MemberAccessExpressionSyntax) { rhs = context.GetFirstNonMachineIdentifier(ret.Expression, model); } var rightSymbol = model.GetSymbolInfo(rhs).Symbol; returnSymbols = new HashSet<ISymbol> { rightSymbol }; HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, rightSymbol, syntaxNode, cfgNode, dataFlowMap)) { foreach (var objectType in objectTypes) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } } else if (ret.Expression is InvocationExpressionSyntax) { var invocation = ret.Expression as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); if (summary != null) { foreach (var objectType in summary.ReturnTypeSet) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } } else if (ret.Expression is ObjectCreationExpressionSyntax) { var objCreation = ret.Expression as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); var objectType = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (objectType != null) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } DataFlowAnalysis.TryCaptureReturnSymbols(returnSymbols, syntaxNode, cfgNode, model, dataFlowMap); } previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; } } else { dataFlowMap.Transfer(previousSyntaxNode, previousCfgNode, cfgNode.SyntaxNodes[0], cfgNode); previousSyntaxNode = cfgNode.SyntaxNodes[0]; previousCfgNode = cfgNode; } foreach (var successor in cfgNode.ISuccessors) { if (DataFlowAnalysis.ReachedFixpoint(previousSyntaxNode, cfgNode, successor, dataFlowMap)) { continue; } DataFlowAnalysis.AnalyseControlFlowGraphNode(successor, cfgNode, previousSyntaxNode, dataFlowMap, model, context); } }
/// <summary> /// Tries to capture a potential field acccess in the given expression. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void TryCaptureFieldAccess(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!(expr is MemberAccessExpressionSyntax)) { return; } var name = (expr as MemberAccessExpressionSyntax).Name; var identifier = context.GetFirstNonMachineIdentifier(expr, model); if (identifier == null || name == null) { return; } var type = model.GetTypeInfo(identifier).Type; if (context.IsTypeAllowedToBeSend(type) || context.IsMachineType(type, model) || name.Equals(identifier)) { return; } var symbol = model.GetSymbolInfo(identifier).Symbol; var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, context.Solution).Result; if (!(definition is IFieldSymbol)) { return; } var fieldDecl = definition.DeclaringSyntaxReferences.First().GetSyntax(). AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First(); if (dataFlowMap.DoesSymbolReset(symbol, cfgNode.Summary.Node.SyntaxNodes.First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { return; } if (cfgNode.Summary.FieldAccessSet.ContainsKey(symbol as IFieldSymbol)) { cfgNode.Summary.FieldAccessSet[symbol as IFieldSymbol].Add(syntaxNode); } else { cfgNode.Summary.FieldAccessSet.Add(symbol as IFieldSymbol, new HashSet<SyntaxNode>()); cfgNode.Summary.FieldAccessSet[symbol as IFieldSymbol].Add(syntaxNode); } }
/// <summary> /// Tries to capture a potential parameter acccess in the given expression. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void TryCaptureParameterAccess(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!(expr is MemberAccessExpressionSyntax)) { return; } var name = (expr as MemberAccessExpressionSyntax).Name; var identifier = context.GetFirstNonMachineIdentifier(expr, model); if (identifier == null || name == null) { return; } var type = model.GetTypeInfo(identifier).Type; if (context.IsTypeAllowedToBeSend(type) || context.IsMachineType(type, model) || name.Equals(identifier)) { return; } var symbol = model.GetSymbolInfo(identifier).Symbol; if (symbol == null) { return; } Dictionary<ISymbol, HashSet<ISymbol>> map = null; if (!dataFlowMap.TryGetMapForSyntaxNode(syntaxNode, cfgNode, out map)) { return; } Dictionary<ISymbol, int> indexMap = new Dictionary<ISymbol, int>(); var parameterList = cfgNode.Summary.Method.ParameterList.Parameters; for (int idx = 0; idx < parameterList.Count; idx++) { var paramSymbol = model.GetDeclaredSymbol(parameterList[idx]); indexMap.Add(paramSymbol, idx); } if (map.ContainsKey(symbol)) { foreach (var reference in map[symbol]) { if (reference.Kind == SymbolKind.Parameter) { if (reference.Equals(symbol) && dataFlowMap.DoesSymbolReset( reference, cfgNode.Summary.Node.SyntaxNodes.First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { continue; } int index = indexMap[reference]; if (cfgNode.Summary.AccessSet.ContainsKey(index)) { cfgNode.Summary.AccessSet[index].Add(syntaxNode); } else { cfgNode.Summary.AccessSet.Add(index, new HashSet<SyntaxNode>()); cfgNode.Summary.AccessSet[index].Add(syntaxNode); } } } } }
/// <summary> /// Tries to get the list of potential methods that can override the given virtual call. /// If it cannot find such methods then it returns false. /// </summary> /// <param name="overriders">List of overrider methods</param> /// <param name="virtualCall">Virtual call</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="originalMachine">Original machine</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> internal static bool TryGetPotentialMethodOverriders(out HashSet<MethodDeclarationSyntax> overriders, InvocationExpressionSyntax virtualCall, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ClassDeclarationSyntax originalMachine, SemanticModel model, AnalysisContext context) { overriders = new HashSet<MethodDeclarationSyntax>(); ISymbol calleeSymbol = null; SimpleNameSyntax callee = null; bool isThis = false; if (virtualCall.Expression is MemberAccessExpressionSyntax) { var expr = virtualCall.Expression as MemberAccessExpressionSyntax; var identifier = expr.Expression.DescendantNodesAndSelf(). OfType<IdentifierNameSyntax>().Last(); calleeSymbol = model.GetSymbolInfo(identifier).Symbol; if (expr.Expression is ThisExpressionSyntax || context.IsMachineType(identifier, model)) { callee = expr.Name; isThis = true; } } else { callee = virtualCall.Expression as IdentifierNameSyntax; isThis = true; } if (isThis) { foreach (var nestedClass in originalMachine.ChildNodes().OfType<ClassDeclarationSyntax>()) { foreach (var method in nestedClass.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return true; } } } foreach (var method in originalMachine.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return true; } } return false; } if (calleeSymbol == null) { return false; } Dictionary<ISymbol, HashSet<ITypeSymbol>> objectTypeMap = null; if (!cfgNode.Summary.DataFlowMap.TryGetObjectTypeMapForSyntaxNode( syntaxNode, cfgNode, out objectTypeMap)) { return false; } if (!objectTypeMap.ContainsKey(calleeSymbol)) { return false; } foreach (var objectType in objectTypeMap[calleeSymbol]) { MethodDeclarationSyntax m = null; if (InheritanceAnalysis.TryGetMethodFromType(out m, objectType, virtualCall, context)) { overriders.Add(m); } } return true; }
/// <summary> /// Tries to get the list of potential methods that can override the given virtual call. /// If it cannot find such methods then it returns false. /// </summary> /// <param name="overriders">List of overrider methods</param> /// <param name="virtualCall">Virtual call</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="originalMachine">Original machine</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean value</returns> internal static bool TryGetPotentialMethodOverriders(out HashSet <MethodDeclarationSyntax> overriders, InvocationExpressionSyntax virtualCall, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ClassDeclarationSyntax originalMachine, SemanticModel model, AnalysisContext context) { overriders = new HashSet <MethodDeclarationSyntax>(); ISymbol calleeSymbol = null; SimpleNameSyntax callee = null; bool isThis = false; if (virtualCall.Expression is MemberAccessExpressionSyntax) { var expr = virtualCall.Expression as MemberAccessExpressionSyntax; var identifier = expr.Expression.DescendantNodesAndSelf(). OfType <IdentifierNameSyntax>().Last(); calleeSymbol = model.GetSymbolInfo(identifier).Symbol; if (expr.Expression is ThisExpressionSyntax || context.IsMachineType(identifier, model)) { callee = expr.Name; isThis = true; } } else { callee = virtualCall.Expression as IdentifierNameSyntax; isThis = true; } if (isThis) { foreach (var nestedClass in originalMachine.ChildNodes().OfType <ClassDeclarationSyntax>()) { foreach (var method in nestedClass.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return(true); } } } foreach (var method in originalMachine.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return(true); } } return(false); } if (calleeSymbol == null) { return(false); } Dictionary <ISymbol, HashSet <ITypeSymbol> > objectTypeMap = null; if (!cfgNode.Summary.DataFlowMap.TryGetObjectTypeMapForSyntaxNode( syntaxNode, cfgNode, out objectTypeMap)) { return(false); } if (!objectTypeMap.ContainsKey(calleeSymbol)) { return(false); } foreach (var objectType in objectTypeMap[calleeSymbol]) { MethodDeclarationSyntax m = null; if (InheritanceAnalysis.TryGetMethodFromType(out m, objectType, virtualCall, context)) { overriders.Add(m); } } return(true); }