private void AddSpecflowStep(IPsiSourceFile targetFile, string classClrName, GherkinStepKind stepKind, string stepText) { var cSharpFile = targetFile.GetProject().GetCSharpFile(targetFile.DisplayName.Substring(targetFile.DisplayName.LastIndexOf('>') + 2)); if (cSharpFile == null) { return; } foreach (var type in cSharpFile.GetChildrenInSubtrees <IClassDeclaration>()) { if (!(type is IClassDeclaration classDeclaration)) { continue; } if (classDeclaration.CLRName != classClrName) { continue; } if (classDeclaration.DeclaredElement?.GetAttributeInstances(AttributesSource.Self).All(x => x.GetAttributeType().GetClrName().FullName != "TechTalk.SpecFlow.Binding") != true) { continue; } var factory = CSharpElementFactory.GetInstance(classDeclaration); var methodName = _stepDefinitionBuilder.GetStepDefinitionMethodNameFromStepText(stepKind, stepText, _reference.IsInsideScenarioOutline()); methodName = cSharpFile.GetPsiServices().Naming.Suggestion.GetDerivedName(methodName, NamedElementKinds.Method, ScopeKind.Common, CSharpLanguage.Instance, new SuggestionOptions(), targetFile); var parameters = _stepDefinitionBuilder.GetStepDefinitionParameters(stepText, _reference.IsInsideScenarioOutline()); var pattern = _stepDefinitionBuilder.GetPattern(stepText, _reference.IsInsideScenarioOutline()); var attributeType = CSharpTypeFactory.CreateType(SpecflowAttributeHelper.GetAttributeClrName(stepKind), classDeclaration.GetPsiModule()); var formatString = $"[$0(@\"$1\")] public void {methodName}() {{ScenarioContext.StepIsPending();}}"; var methodDeclaration = factory.CreateTypeMemberDeclaration(formatString, attributeType, pattern.Replace("\"", "\"\"")) as IMethodDeclaration; if (methodDeclaration == null) { continue; } var psiModule = classDeclaration.GetPsiModule(); foreach (var(parameterName, parameterType) in parameters) { methodDeclaration.AddParameterDeclarationAfter(ParameterKind.VALUE, CSharpTypeFactory.CreateType(parameterType, psiModule), parameterName, null); } IClassMemberDeclaration insertedDeclaration; using (new PsiTransactionCookie(type.GetPsiServices(), DefaultAction.Commit, "Generate specflow step")) { insertedDeclaration = classDeclaration.AddClassMemberDeclaration((IClassMemberDeclaration)methodDeclaration); } var invocationExpression = insertedDeclaration.GetChildrenInSubtrees <IInvocationExpression>().FirstOrDefault(); if (invocationExpression != null) { invocationExpression.NavigateToNode(true); } else { insertedDeclaration.NavigateToNode(true); } } }
public void ProcessBeforeInterior(ITreeNode element, FilteringHighlightingConsumer context) { if (!(element is IMethodDeclaration method)) { return; } var psiServices = method.GetPsiServices(); var invalidNames = new LocalList <string>(); foreach (var attribute in method.Attributes) { var stepKind = SpecflowAttributeHelper.GetAttributeStepKind(attribute.GetAttributeType().GetClrName()); if (stepKind == null) { continue; } var attributeInstance = attribute.GetAttributeInstance(); if (attributeInstance.PositionParameterCount < 1) { continue; } var constantValue = attributeInstance.PositionParameter(0).ConstantValue; if (!constantValue.IsValid()) { continue; } if (!(constantValue.Value is string stepText)) { continue; } var expectedMethodName = SpecflowStepHelper.GetMethodNameAndParameterFromStepPattern(stepKind.Value, stepText, psiServices, _daemonProcess.SourceFile, method.Params.ParameterDeclarations.Select(x => x.DeclaredName).ToList()); if (string.Equals(method.DeclaredName, expectedMethodName, StringComparison.InvariantCultureIgnoreCase)) { return; } if (method.DeclaredName.ToLowerInvariant().StartsWith(stepKind.ToString().ToLowerInvariant())) { invalidNames.Insert(0, expectedMethodName); } else { invalidNames.Add(expectedMethodName); } } if (invalidNames.Count > 0) { var expectedName = invalidNames.FirstOrDefault(); context.AddHighlighting(new MethodNameMismatchPatternInfo(method, expectedName)); } }
public object Build(IPsiAssembly assembly) { SpecflowStepsDefinitionsCacheEntries stepDefinitions = null; _psiAssemblyFileLoader.GetOrLoadAssembly(assembly, true, (psiAssembly, assemblyFile, metadataAssembly) => { stepDefinitions = new SpecflowStepsDefinitionsCacheEntries(); foreach (var type in metadataAssembly.GetTypes()) { if (type.CustomAttributesTypeNames.All(a => a.FullName.GetText() != SpecflowAttributeHelper.BindingAttribute.FullName)) { continue; } var classCacheEntry = new SpecflowStepDefinitionCacheClassEntry(type.FullyQualifiedName, true); foreach (var method in type.GetMethods().Where(x => x.IsPublic)) { // FIXME: We should avoid adding method that are not step here (it's just using more memory) var methodCacheEntry = classCacheEntry.AddMethod(method.Name); for (var index = 0; index < method.CustomAttributes.Length; index++) { var attributeInstance = method.CustomAttributes[index]; if (attributeInstance.ConstructorArguments.Length == 0) { continue; } var regex = attributeInstance.ConstructorArguments[0].Value as string; if (regex == null) { continue; } var attributeTypeName = method.CustomAttributesTypeNames[index].FullName.ToString(); if (SpecflowAttributeHelper.IsAttributeForKind(GherkinStepKind.Given, attributeTypeName)) { methodCacheEntry.AddStep(GherkinStepKind.Given, regex); } if (SpecflowAttributeHelper.IsAttributeForKind(GherkinStepKind.When, attributeTypeName)) { methodCacheEntry.AddStep(GherkinStepKind.When, regex); } if (SpecflowAttributeHelper.IsAttributeForKind(GherkinStepKind.Then, attributeTypeName)) { methodCacheEntry.AddStep(GherkinStepKind.Then, regex); } } } stepDefinitions.Add(classCacheEntry); } }); return(stepDefinitions); }
private SpecflowStepDefinitionCacheClassEntry BuildBindingClassCacheEntry(IClassDeclaration classDeclaration, bool hasSpecflowBindingAttribute) { var classCacheEntry = new SpecflowStepDefinitionCacheClassEntry(classDeclaration.CLRName, hasSpecflowBindingAttribute); foreach (var member in classDeclaration.MemberDeclarations) { if (!(member is IMethodDeclaration methodDeclaration)) { continue; } var methodCacheEntry = classCacheEntry.AddMethod(methodDeclaration.DeclaredName); foreach (var attributeInstance in methodDeclaration.Attributes.Select(x => x.GetAttributeInstance())) { if (attributeInstance.PositionParameterCount == 0) { continue; } var parameter = attributeInstance.PositionParameter(0); var regex = parameter.ConstantValue.Value as string; if (regex == null) { continue; } if (SpecflowAttributeHelper.IsAttributeForKind(GherkinStepKind.Given, attributeInstance.GetAttributeType().GetClrName())) { methodCacheEntry.AddStep(GherkinStepKind.Given, regex); } if (SpecflowAttributeHelper.IsAttributeForKind(GherkinStepKind.When, attributeInstance.GetAttributeType().GetClrName())) { methodCacheEntry.AddStep(GherkinStepKind.When, regex); } if (SpecflowAttributeHelper.IsAttributeForKind(GherkinStepKind.Then, attributeInstance.GetAttributeType().GetClrName())) { methodCacheEntry.AddStep(GherkinStepKind.Then, regex); } } } return(classCacheEntry); }
public void ProcessBeforeInterior(ITreeNode element, FilteringHighlightingConsumer context) { if (!(element is IMethodDeclaration method)) { return; } var psiServices = method.GetPsiServices(); var invalidNames = new LocalList <string>(); foreach (var attribute in method.Attributes) { var stepKind = SpecflowAttributeHelper.GetAttributeStepKind(attribute.GetAttributeType().GetClrName()); if (stepKind == null) { continue; } var attributeInstance = attribute.GetAttributeInstance(); if (attributeInstance.PositionParameterCount < 1) { continue; } var constantValue = attributeInstance.PositionParameter(0).ConstantValue; if (!constantValue.IsValid()) { continue; } if (!(constantValue.Value is string stepText)) { continue; } if (method.DeclaredElement == null) { continue; } var expectedMethodName = _stepDefinitionBuilder.GetStepDefinitionMethodNameFromPattern(stepKind.Value, stepText, method.DeclaredElement.Parameters.SelectNotNull(x => x.ShortName).ToArray()); expectedMethodName = psiServices.Naming.Suggestion.GetDerivedName(expectedMethodName, NamedElementKinds.Method, ScopeKind.Common, CSharpLanguage.Instance.NotNull(), new SuggestionOptions(), _daemonProcess.SourceFile); if (string.Equals(method.DeclaredName, expectedMethodName, StringComparison.InvariantCultureIgnoreCase)) { return; } if (method.DeclaredName.ToLowerInvariant().StartsWith(stepKind.ToString().ToLowerInvariant())) { invalidNames.Insert(0, expectedMethodName); } else { invalidNames.Add(expectedMethodName); } } if (invalidNames.Count > 0) { var expectedName = invalidNames.FirstOrDefault(); context.AddHighlighting(new MethodNameMismatchPatternInfo(method, expectedName)); } }