Exemple #1
0
        /// <summary>
        /// Returns true if the given class declaration is a P# machine state.
        /// </summary>
        /// <param name="compilation">Compilation</param>
        /// <param name="classDecl">Class declaration</param>
        /// <returns>Boolean value</returns>
        internal static bool IsMachineState(CodeAnalysis.Compilation compilation, ClassDeclarationSyntax classDecl)
        {
            var result = false;

            if (classDecl.BaseList == null)
            {
                return(result);
            }

            var model  = compilation.GetSemanticModel(classDecl.SyntaxTree);
            var symbol = model.GetDeclaredSymbol(classDecl);

            while (true)
            {
                if (symbol.ToString() == typeof(MachineState).FullName)
                {
                    result = true;
                    break;
                }
                else if (symbol.BaseType != null)
                {
                    symbol = symbol.BaseType;
                    continue;
                }

                break;
            }

            return(result);
        }
        /// <summary>
        /// Checks for multiple handlers for the same event.
        /// </summary>
        /// <param name="state">State</param>
        /// <param name="compilation">Compilation</param>
        private void CheckForMultipleSameEventHandlers(ClassDeclarationSyntax state, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(state.SyntaxTree);

            var eventHandlers = state.AttributeLists.
                                SelectMany(val => val.Attributes).
                                Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventGotoState") ||
                                      model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventPushState") ||
                                      model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventDoAction") ||
                                      model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.IgnoreEvents") ||
                                      model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.DeferEvents")).
                                Where(val => val.ArgumentList != null).
                                Where(val => val.ArgumentList.Arguments.Count > 0).
                                Where(val => val.ArgumentList.Arguments[0].Expression is TypeOfExpressionSyntax).
                                Select(val => val.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).
                                Select(val => val.Type as IdentifierNameSyntax).
                                Select(val => val.Identifier.ValueText).
                                ToList();

            var eventOccurrences = eventHandlers.GroupBy(val => val);

            foreach (var e in eventOccurrences.Where(val => val.Count() > 1))
            {
                base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                               "' cannot declare more than one handler for event '" + e.Key + "'."));
            }
        }
        /// <summary>
        /// Checks that a state does not have a duplicate liveness attribute.
        /// </summary>
        /// <param name="state">State</param>
        /// <param name="compilation">Compilation</param>
        private void CheckForDuplicateLivenessAttributes(ClassDeclarationSyntax state, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(state.SyntaxTree);

            var hotAttributes = state.AttributeLists.
                                SelectMany(val => val.Attributes).
                                Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.Hot")).
                                ToList();

            var coldAttributes = state.AttributeLists.
                                 SelectMany(val => val.Attributes).
                                 Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.Cold")).
                                 ToList();

            if (hotAttributes.Count > 0 && coldAttributes.Count > 0)
            {
                base.ErrorLog.Add(Tuple.Create(state.Identifier, "A monitor state cannot declare both " +
                                               "hot and cold liveness attributes."));
            }
        }
        /// <summary>
        /// Checks that a state does not have a duplicate exit action.
        /// </summary>
        /// <param name="state">State</param>
        /// <param name="compilation">Compilation</param>
        private void CheckForDuplicateOnExit(ClassDeclarationSyntax state, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(state.SyntaxTree);

            var onExitAttribute = state.AttributeLists.
                                  SelectMany(val => val.Attributes).
                                  Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnExit")).
                                  FirstOrDefault();

            var onExitMethod = state.DescendantNodes().OfType <MethodDeclarationSyntax>().
                               Where(val => val.Modifiers.Any(SyntaxKind.OverrideKeyword)).
                               Where(val => val.Identifier.ValueText.Equals("OnExit")).
                               FirstOrDefault();

            if (onExitAttribute != null && onExitMethod != null)
            {
                base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" +
                                               state.Identifier.ValueText + "' cannot have two exit actions."));
            }
        }
Exemple #5
0
        /// <summary>
        /// Checks that a machine has an start state.
        /// </summary>
        /// <param name="machine">Machine</param>
        /// <param name="compilation">Compilation</param>
        private void CheckForStartState(ClassDeclarationSyntax machine, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(machine.SyntaxTree);

            var stateAttributes = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                  Where(val => this.IsState(compilation, val)).
                                  SelectMany(val => val.AttributeLists).
                                  SelectMany(val => val.Attributes).
                                  Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.Start")).
                                  ToList();

            if (stateAttributes.Count == 0)
            {
                base.ErrorLog.Add(Tuple.Create(machine.Identifier, this.GetTypeOfMachine().ToLower() + " '" +
                                               machine.Identifier.ValueText + "' must declare a start state."));
            }
            else if (stateAttributes.Count > 1)
            {
                base.ErrorLog.Add(Tuple.Create(machine.Identifier, this.GetTypeOfMachine().ToLower() + " '" +
                                               machine.Identifier.ValueText + "' must declare only one start state."));
            }
        }
Exemple #6
0
        /// <summary>
        /// Checks that a machine has an start state.
        /// </summary>
        private void CheckForStartState(ClassDeclarationSyntax machine, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(machine.SyntaxTree);

            var stateAttributes = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                  Where(val => this.IsState(compilation, val)).
                                  SelectMany(val => val.AttributeLists).
                                  SelectMany(val => val.Attributes).
                                  Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.Start")).
                                  ToList();

            if (stateAttributes.Count == 0)
            {
                this.WarningLog.Add(Tuple.Create(machine.Identifier, $"{this.GetTypeOfMachine().ToLower()} " +
                                                 $"'{machine.Identifier.ValueText}' must declare a start state (unless the machine " +
                                                 "inherits a start state from a base machine, or is partial, and one state has been " +
                                                 "already declared in another part of the declaration)."));
            }
            else if (stateAttributes.Count > 1)
            {
                this.ErrorLog.Add(Tuple.Create(machine.Identifier, $"{this.GetTypeOfMachine().ToLower()} " +
                                               $"'{machine.Identifier.ValueText}' must declare only one start state."));
            }
        }
Exemple #7
0
        /// <summary>
        /// Discovers the available actions of the given machine.
        /// </summary>
        /// <param name="machine">Machine</param>
        /// <param name="compilation">Compilation</param>
        private void DiscoverMachineActions(ClassDeclarationSyntax machine, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(machine.SyntaxTree);

            var onEntryActionNames = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                     Where(val => this.IsState(compilation, val)).
                                     SelectMany(val => val.AttributeLists).
                                     SelectMany(val => val.Attributes).
                                     Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEntry")).
                                     Where(val => val.ArgumentList != null).
                                     Where(val => val.ArgumentList.Arguments.Count == 1).
                                     Where(val => val.ArgumentList.Arguments[0].Expression is LiteralExpressionSyntax).
                                     Select(val => val.ArgumentList.Arguments[0].Expression as LiteralExpressionSyntax).
                                     Select(val => val.Token.ValueText).
                                     ToList();

            var onEntryNameOfActionNames = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                           Where(val => this.IsState(compilation, val)).
                                           SelectMany(val => val.AttributeLists).
                                           SelectMany(val => val.Attributes).
                                           Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEntry")).
                                           Where(val => val.ArgumentList != null).
                                           Where(val => val.ArgumentList.Arguments.Count == 1).
                                           Where(val => val.ArgumentList.Arguments[0].Expression is InvocationExpressionSyntax).
                                           Select(val => val.ArgumentList.Arguments[0].Expression as InvocationExpressionSyntax).
                                           Where(val => val.Expression is IdentifierNameSyntax).
                                           Where(val => (val.Expression as IdentifierNameSyntax).Identifier.ValueText.Equals("nameof")).
                                           Where(val => val.ArgumentList != null).
                                           Where(val => val.ArgumentList.Arguments.Count == 1).
                                           Where(val => val.ArgumentList.Arguments[0].Expression is IdentifierNameSyntax).
                                           Select(val => val.ArgumentList.Arguments[0].Expression as IdentifierNameSyntax).
                                           Select(val => val.Identifier.ValueText).
                                           ToList();

            var onExitActionNames = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                    Where(val => this.IsState(compilation, val)).
                                    SelectMany(val => val.AttributeLists).
                                    SelectMany(val => val.Attributes).
                                    Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnExit")).
                                    Where(val => val.ArgumentList != null).
                                    Where(val => val.ArgumentList.Arguments.Count == 1).
                                    Where(val => val.ArgumentList.Arguments[0].Expression is LiteralExpressionSyntax).
                                    Select(val => val.ArgumentList.Arguments[0].Expression as LiteralExpressionSyntax).
                                    Select(val => val.Token.ValueText).
                                    ToList();

            var onExitNameOfActionNames = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                          Where(val => this.IsState(compilation, val)).
                                          SelectMany(val => val.AttributeLists).
                                          SelectMany(val => val.Attributes).
                                          Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnExit")).
                                          Where(val => val.ArgumentList != null).
                                          Where(val => val.ArgumentList.Arguments.Count == 1).
                                          Where(val => val.ArgumentList.Arguments[0].Expression is InvocationExpressionSyntax).
                                          Select(val => val.ArgumentList.Arguments[0].Expression as InvocationExpressionSyntax).
                                          Where(val => val.Expression is IdentifierNameSyntax).
                                          Where(val => (val.Expression as IdentifierNameSyntax).Identifier.ValueText.Equals("nameof")).
                                          Where(val => val.ArgumentList != null).
                                          Where(val => val.ArgumentList.Arguments.Count == 1).
                                          Where(val => val.ArgumentList.Arguments[0].Expression is IdentifierNameSyntax).
                                          Select(val => val.ArgumentList.Arguments[0].Expression as IdentifierNameSyntax).
                                          Select(val => val.Identifier.ValueText).
                                          ToList();

            var onEventDoActionNames = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                       Where(val => this.IsState(compilation, val)).
                                       SelectMany(val => val.AttributeLists).
                                       SelectMany(val => val.Attributes).
                                       Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventDoAction")).
                                       Where(val => val.ArgumentList != null).
                                       Where(val => val.ArgumentList.Arguments.Count == 2).
                                       Where(val => val.ArgumentList.Arguments[1].Expression is LiteralExpressionSyntax).
                                       Select(val => val.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax).
                                       Select(val => val.Token.ValueText).
                                       ToList();

            var onEventDoNameOfActionNames = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                                             Where(val => this.IsState(compilation, val)).
                                             SelectMany(val => val.AttributeLists).
                                             SelectMany(val => val.Attributes).
                                             Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventDoAction")).
                                             Where(val => val.ArgumentList != null).
                                             Where(val => val.ArgumentList.Arguments.Count == 2).
                                             Where(val => val.ArgumentList.Arguments[1].Expression is InvocationExpressionSyntax).
                                             Select(val => val.ArgumentList.Arguments[1].Expression as InvocationExpressionSyntax).
                                             Where(val => val.Expression is IdentifierNameSyntax).
                                             Where(val => (val.Expression as IdentifierNameSyntax).Identifier.ValueText.Equals("nameof")).
                                             Where(val => val.ArgumentList != null).
                                             Where(val => val.ArgumentList.Arguments.Count == 1).
                                             Where(val => val.ArgumentList.Arguments[0].Expression is IdentifierNameSyntax).
                                             Select(val => val.ArgumentList.Arguments[0].Expression as IdentifierNameSyntax).
                                             Select(val => val.Identifier.ValueText).
                                             ToList();

            var actionNames = new HashSet <string>();

            actionNames.UnionWith(onEntryActionNames);
            actionNames.UnionWith(onEntryNameOfActionNames);
            actionNames.UnionWith(onExitActionNames);
            actionNames.UnionWith(onExitNameOfActionNames);
            actionNames.UnionWith(onEventDoActionNames);
            actionNames.UnionWith(onEventDoNameOfActionNames);

            this.Actions.Add(machine, new List <MethodDeclarationSyntax>());

            foreach (var actionName in actionNames)
            {
                var action = machine.DescendantNodes().OfType <MethodDeclarationSyntax>().
                             Where(val => val.ParameterList != null).
                             Where(val => val.ParameterList.Parameters.Count == 0).
                             Where(val => val.Identifier.ValueText.Equals(actionName)).
                             FirstOrDefault();

                if (action != null)
                {
                    this.Actions[machine].Add(action);
                }
            }

            var states = machine.DescendantNodes().OfType <ClassDeclarationSyntax>().
                         Where(val => this.IsState(compilation, val)).
                         ToList();

            var stateMethods = states.SelectMany(val => val.DescendantNodes().OfType <MethodDeclarationSyntax>()).
                               Where(val => val.Modifiers.Any(SyntaxKind.OverrideKeyword)).
                               ToList();

            foreach (var method in stateMethods)
            {
                this.Actions[machine].Add(method);
            }
        }
Exemple #8
0
        /// <summary>
        /// Checks for correct wildcard usage.
        /// If "defer *" then:
        ///    no other event should be deferred.
        /// If "ignore *" or "on * do action" then:
        ///    no other action or ignore should be defined.
        /// If "On * goto" or "On * push" then:
        ///    no other transition, action or ignore should be defined.
        /// </summary>
        /// <param name="state">State</param>
        /// <param name="compilation">Compilation</param>
        private void CheckForCorrectWildcardUse(ClassDeclarationSyntax state, CodeAnalysis.Compilation compilation)
        {
            var model = compilation.GetSemanticModel(state.SyntaxTree);

            var ignoreTypes = state.AttributeLists.
                              SelectMany(val => val.Attributes).
                              Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.IgnoreEvents")).
                              Where(val => val.ArgumentList != null).
                              Where(val => val.ArgumentList.Arguments.Count > 0).
                              SelectMany(val => val.ArgumentList.Arguments).
                              Where(val => val.Expression is TypeOfExpressionSyntax).
                              Select(val => val.Expression as TypeOfExpressionSyntax);

            var deferTypes = state.AttributeLists.
                             SelectMany(val => val.Attributes).
                             Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.DeferEvents")).
                             Where(val => val.ArgumentList != null).
                             Where(val => val.ArgumentList.Arguments.Count > 0).
                             SelectMany(val => val.ArgumentList.Arguments).
                             Where(val => val.Expression is TypeOfExpressionSyntax).
                             Select(val => val.Expression as TypeOfExpressionSyntax);

            var actionTypes = state.AttributeLists.
                              SelectMany(val => val.Attributes).
                              Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventDoAction")).
                              Where(val => val.ArgumentList != null).
                              Where(val => val.ArgumentList.Arguments.Count > 0).
                              Where(val => val.ArgumentList.Arguments[0].Expression is TypeOfExpressionSyntax).
                              Select(val => val.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax);

            var transitionTypes = state.AttributeLists.
                                  SelectMany(val => val.Attributes).
                                  Where(val => model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventGotoState") ||
                                        model.GetTypeInfo(val).Type.ToDisplayString().Equals("Microsoft.PSharp.OnEventPushState")).
                                  Where(val => val.ArgumentList != null).
                                  Where(val => val.ArgumentList.Arguments.Count > 0).
                                  Where(val => val.ArgumentList.Arguments[0].Expression is TypeOfExpressionSyntax).
                                  Select(val => val.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax);

            var convertToStringSet = new Func <IEnumerable <TypeOfExpressionSyntax>, HashSet <string> >(ls =>
            {
                var eventHandlers = new HashSet <string>(ls.
                                                         Where(val => val.Type is IdentifierNameSyntax).
                                                         Select(val => val.Type as IdentifierNameSyntax).
                                                         Select(val => val.ToFullString()));

                eventHandlers.UnionWith(ls.
                                        Where(val => val.Type is QualifiedNameSyntax).
                                        Select(val => val.Type as QualifiedNameSyntax).
                                        Select(val => val.ToFullString()));

                return(eventHandlers);
            });

            var ignoredEvents    = convertToStringSet(ignoreTypes);
            var deferredEvents   = convertToStringSet(deferTypes);
            var actionEvents     = convertToStringSet(actionTypes);
            var transitionEvents = convertToStringSet(transitionTypes);

            var isWildCard  = new Func <string, bool>(s => s == "WildCardEvent" || s == "Microsoft.PSharp.WildCardEvent");
            var hasWildCard = new Func <HashSet <string>, bool>(set => set.Contains("WildCardEvent") ||
                                                                set.Contains("Microsoft.PSharp.WildCardEvent"));

            if (hasWildCard(deferredEvents))
            {
                foreach (var e in deferredEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot defer other event '" + e + "' when deferring the wildcard event."));
                }
            }

            if (hasWildCard(ignoredEvents))
            {
                foreach (var e in ignoredEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot ignore other event '" + e + "' when ignoring the wildcard event."));
                }

                foreach (var e in actionEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot define action on '" + e + "' when ignoring the wildcard event."));
                }
            }

            if (hasWildCard(actionEvents))
            {
                foreach (var e in ignoredEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot ignore other event '" + e + "' when defining an action on the wildcard event."));
                }

                foreach (var e in actionEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot define action on '" + e + "' when defining an action on the wildcard event."));
                }
            }

            if (hasWildCard(transitionEvents))
            {
                foreach (var e in ignoredEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot ignore other event '" + e + "' when defining a transition on the wildcard event."));
                }

                foreach (var e in actionEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot define action on '" + e + "' when defining a transition on the wildcard event."));
                }

                foreach (var e in transitionEvents.Where(s => !isWildCard(s)))
                {
                    base.ErrorLog.Add(Tuple.Create(state.Identifier, "State '" + state.Identifier.ValueText +
                                                   "' cannot define a transition on '" + e + "' when defining a transition on the wildcard event."));
                }
            }
        }