public static Document GetDocumentForSymbol(this Compilation compilation, Solution solution, string name) { var relatedSymbols = compilation.GetSymbolsWithName(p => p == name, SymbolFilter.Type) .ToList(); if (relatedSymbols.Count != 1) { return(null); } var symbol = relatedSymbols.First() as ITypeSymbol; if (symbol.TypeKind == TypeKind.Enum) { return(null); } var location = relatedSymbols .Select(p => p.Locations.FirstOrDefault()) .FirstOrDefault(); var docId = solution .GetDocumentIdsWithFilePath(location.SourceTree.FilePath) .FirstOrDefault(); return(solution.GetDocument(docId)); }
private static async Task <GenerationResult> GenerateAsync(bool withRegeneration, IUnitTestGeneratorOptions options, Solution solution, GenerationItem generationItem, SemanticModel semanticModel) { GenerationResult result; if (File.Exists(generationItem.TargetFileName)) { var documentIds = solution.GetDocumentIdsWithFilePath(generationItem.TargetFileName); if (documentIds.FirstOrDefault() is DocumentId targetDocumentId) { var targetDocument = solution.GetDocument(targetDocumentId); var targetSemanticModel = await targetDocument.GetSemanticModelAsync().ConfigureAwait(true); result = await CoreGenerator.Generate(semanticModel, generationItem.SourceSymbol, targetSemanticModel, withRegeneration, options, generationItem.NamespaceTransform).ConfigureAwait(true); } else { result = await CoreGenerator.Generate(semanticModel, generationItem.SourceSymbol, null, withRegeneration, options, generationItem.NamespaceTransform).ConfigureAwait(true); } } else { result = await CoreGenerator.Generate(semanticModel, generationItem.SourceSymbol, null, withRegeneration, options, generationItem.NamespaceTransform).ConfigureAwait(true); } return(result); }
private async Task <LinkedFileMergeResult> MergeLinkedDocumentGroupAsync( IEnumerable <DocumentId> allLinkedDocuments, IEnumerable <DocumentId> linkedDocumentGroup, LinkedFileDiffMergingSessionInfo sessionInfo, IMergeConflictHandler mergeConflictHandler, CancellationToken cancellationToken) { var groupSessionInfo = new LinkedFileGroupSessionInfo(); // Automatically merge non-conflicting diffs while collecting the conflicting diffs var textDifferencingService = _oldSolution.Workspace.Services.GetService <IDocumentTextDifferencingService>() ?? new DefaultDocumentTextDifferencingService(); var appliedChanges = await textDifferencingService.GetTextChangesAsync(_oldSolution.GetDocument(linkedDocumentGroup.First()), _newSolution.GetDocument(linkedDocumentGroup.First()), cancellationToken).ConfigureAwait(false); var unmergedChanges = new List <UnmergedDocumentChanges>(); foreach (var documentId in linkedDocumentGroup.Skip(1)) { appliedChanges = await AddDocumentMergeChangesAsync( _oldSolution.GetDocument(documentId), _newSolution.GetDocument(documentId), appliedChanges.ToList(), unmergedChanges, groupSessionInfo, textDifferencingService, cancellationToken).ConfigureAwait(false); } var originalDocument = _oldSolution.GetDocument(linkedDocumentGroup.First()); var originalSourceText = await originalDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); // Add comments in source explaining diffs that could not be merged IEnumerable <TextChange> allChanges; IList <TextSpan> mergeConflictResolutionSpan = new List <TextSpan>(); if (unmergedChanges.Any()) { mergeConflictHandler ??= _oldSolution.GetDocument(linkedDocumentGroup.First()).GetLanguageService <ILinkedFileMergeConflictCommentAdditionService>(); var mergeConflictTextEdits = mergeConflictHandler.CreateEdits(originalSourceText, unmergedChanges); allChanges = MergeChangesWithMergeFailComments(appliedChanges, mergeConflictTextEdits, mergeConflictResolutionSpan, groupSessionInfo); } else { allChanges = appliedChanges; } groupSessionInfo.LinkedDocuments = _newSolution.GetDocumentIdsWithFilePath(originalDocument.FilePath).Length; groupSessionInfo.DocumentsWithChanges = linkedDocumentGroup.Count(); sessionInfo.LogLinkedFileResult(groupSessionInfo); return(new LinkedFileMergeResult(allLinkedDocuments, originalSourceText.WithChanges(allChanges), mergeConflictResolutionSpan)); }
private static async Task GenerateItemAsync(bool withRegeneration, IUnitTestGeneratorOptions options, Solution solution, GenerationItem generationItem) { var targetProject = solution.Projects.FirstOrDefault(x => string.Equals(x.Name, generationItem.Source.SourceProjectName, StringComparison.Ordinal)); var documents = solution.GetDocumentIdsWithFilePath(generationItem.Source.FilePath); var documentId = documents.FirstOrDefault(x => x.ProjectId == targetProject?.Id) ?? documents.FirstOrDefault(); if (documentId == null) { throw new InvalidOperationException("Could not find document in solution with file path '" + generationItem.Source.FilePath + "'"); } var document = solution.GetDocument(documentId); var semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(true); var tree = await semanticModel.SyntaxTree.GetRootAsync().ConfigureAwait(true); if (!tree.DescendantNodes().OfType <ClassDeclarationSyntax>().Any() && !tree.DescendantNodes().OfType <StructDeclarationSyntax>().Any()) { return; } var result = await GenerateAsync(withRegeneration, options, solution, generationItem, semanticModel).ConfigureAwait(true); generationItem.TargetContent = result.FileContent; foreach (var asset in result.RequiredAssets) { generationItem.RequiredAssets.Add(asset); } foreach (var reference in result.AssemblyReferences) { if (!generationItem.AssemblyReferences.Any(x => string.Equals(x.Name, reference.Name, StringComparison.OrdinalIgnoreCase))) { generationItem.AssemblyReferences.Add(reference); } } }
/// <summary> /// 現在選択している型を取得します。 /// </summary> private async Task <INamedTypeSymbol> GetSelectedTypeSymbolAsync(Microsoft.CodeAnalysis.Solution solution) { var activeDoc = _dte.ActiveDocument; if (activeDoc == null) { return(null); } var docId = solution.GetDocumentIdsWithFilePath(activeDoc.FullName).FirstOrDefault(); if (docId == null) { return(null); } var doc = solution.GetDocument(docId); var selection = (TextSelection)activeDoc.Selection; var position = (selection.ActivePoint.AbsoluteCharOffset - 1) + (selection.CurrentLine - 1); var symbol = await SymbolFinder.FindSymbolAtPositionAsync(doc, position); return(FindTypeSymbol(symbol)); }
private void AddActiveStatements(Solution solution, ShellInterop.ENC_ACTIVE_STATEMENT[] vsActiveStatements) { Debug.Assert(_activeMethods.Count == 0); Debug.Assert(_exceptionRegions.Count == 0); foreach (var vsActiveStatement in vsActiveStatements) { log.DebugWrite("+AS[{0}]: {1} {2} {3} {4} '{5}'", vsActiveStatement.id, vsActiveStatement.tsPosition.iStartLine, vsActiveStatement.tsPosition.iStartIndex, vsActiveStatement.tsPosition.iEndLine, vsActiveStatement.tsPosition.iEndIndex, vsActiveStatement.filename); // TODO (tomat): // Active statement is in user hidden code. The only information that we have from the debugger // is the method token. We don't need to track the statement (it's not in user code anyways), // but we should probably track the list of such methods in order to preserve their local variables. // Not sure what's exactly the scenario here, perhaps modifying async method/iterator? // Dev12 just ignores these. if (vsActiveStatement.posType != TEXT_POSITION_ACTIVE_STATEMENT) { continue; } var flags = (ActiveStatementFlags)vsActiveStatement.ASINFO; // Finds a document id in the solution with the specified file path. DocumentId documentId = solution.GetDocumentIdsWithFilePath(vsActiveStatement.filename) .Where(dId => dId.ProjectId == _vsProject.Id).SingleOrDefault(); if (documentId != null) { var document = solution.GetDocument(documentId); Debug.Assert(document != null); SourceText source = document.GetTextAsync(default(CancellationToken)).Result; LinePositionSpan lineSpan = vsActiveStatement.tsPosition.ToLinePositionSpan(); // If the PDB is out of sync with the source we might get bad spans. var sourceLines = source.Lines; if (lineSpan.End.Line >= sourceLines.Count || sourceLines.GetPosition(lineSpan.End) > sourceLines[sourceLines.Count - 1].EndIncludingLineBreak) { log.Write("AS out of bounds (line count is {0})", source.Lines.Count); continue; } SyntaxNode syntaxRoot = document.GetSyntaxRootAsync(default(CancellationToken)).Result; var analyzer = document.Project.LanguageServices.GetService<IEditAndContinueAnalyzer>(); s_pendingActiveStatements.Add(new VsActiveStatement( this, vsActiveStatement.id, document.Id, new ActiveStatementSpan(flags, lineSpan))); bool isLeaf = (flags & ActiveStatementFlags.LeafFrame) != 0; var ehRegions = analyzer.GetExceptionRegions(source, syntaxRoot, lineSpan, isLeaf); for (int i = 0; i < ehRegions.Length; i++) { _exceptionRegions.Add(new VsExceptionRegion( vsActiveStatement.id, i, vsActiveStatement.methodToken, ehRegions[i])); } } _activeMethods.Add(vsActiveStatement.methodToken); } }
private async Task <string> GenerateUnitTestContentsFromFileAsync(string inputFilePath) { Microsoft.CodeAnalysis.Solution solution = CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace.CurrentSolution; DocumentId documentId = solution.GetDocumentIdsWithFilePath(inputFilePath).FirstOrDefault(); if (documentId == null) { this.HandleError("Could not find document in solution with file path " + inputFilePath); } var document = solution.GetDocument(documentId); SyntaxNode root = await document.GetSyntaxRootAsync(); SemanticModel semanticModel = await document.GetSemanticModelAsync(); SyntaxNode firstClassDeclaration = root.DescendantNodes().FirstOrDefault(node => node.Kind() == SyntaxKind.ClassDeclaration); if (firstClassDeclaration == null) { this.HandleError("Could not find class declaration."); } if (firstClassDeclaration.ChildTokens().Any(node => node.Kind() == SyntaxKind.AbstractKeyword)) { this.HandleError("Cannot unit test an abstract class."); } SyntaxToken classIdentifierToken = firstClassDeclaration.ChildTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierToken); if (classIdentifierToken == null) { this.HandleError("Could not find class identifier."); } NamespaceDeclarationSyntax namespaceDeclarationSyntax = null; if (!Utilities.TryGetParentSyntax(firstClassDeclaration, out namespaceDeclarationSyntax)) { this.HandleError("Could not find class namespace."); } // Find property injection types var injectableProperties = new List <InjectableProperty>(); string classFullName = namespaceDeclarationSyntax.Name + "." + classIdentifierToken; INamedTypeSymbol classType = semanticModel.Compilation.GetTypeByMetadataName(classFullName); foreach (ISymbol member in classType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers())) { if (member.Kind == SymbolKind.Property) { IPropertySymbol property = (IPropertySymbol)member; foreach (AttributeData attribute in property.GetAttributes()) { if (attribute.AttributeClass.ToString() == "Microsoft.Practices.Unity.DependencyAttribute") { injectableProperties.Add(new InjectableProperty(property.Name, property.Type.Name, property.Type.ContainingNamespace.ToString())); } } } } this.className = classIdentifierToken.ToString(); // Find constructor injection types var constructorInjectionTypes = new List <InjectableType>(); SyntaxNode constructorDeclaration = firstClassDeclaration.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.ConstructorDeclaration); if (constructorDeclaration != null) { SyntaxNode parameterListNode = constructorDeclaration.ChildNodes().First(n => n.Kind() == SyntaxKind.ParameterList); var parameterNodes = parameterListNode.ChildNodes().Where(n => n.Kind() == SyntaxKind.Parameter); foreach (SyntaxNode node in parameterNodes) { SyntaxNode identifierNode = node.ChildNodes().First(n => n.Kind() == SyntaxKind.IdentifierName); SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(identifierNode); constructorInjectionTypes.Add( new InjectableType( symbolInfo.Symbol.Name, symbolInfo.Symbol.ContainingNamespace.ToString())); } } string unitTestNamespace; string defaultNamespace = this.SelectedProject.Project.Properties.Item("DefaultNamespace").Value as string; if (string.IsNullOrEmpty(this.relativePath)) { unitTestNamespace = defaultNamespace; } else { List <string> defaultNamespaceParts = defaultNamespace.Split('.').ToList(); List <string> unitTestNamespaceParts = new List <string>(defaultNamespaceParts); unitTestNamespaceParts.AddRange(this.relativePath.Split('\\')); unitTestNamespace = string.Join(".", unitTestNamespaceParts); } return(this.GenerateUnitTestContents( unitTestNamespace, this.className, namespaceDeclarationSyntax.Name.ToString(), injectableProperties, constructorInjectionTypes)); }
private static Document GetDocument(Solution solution, string fname) { var docId = solution.GetDocumentIdsWithFilePath(fname).First(); var doc = solution.GetDocument(docId); return doc; }
private async Task <TestGenerationContext> CollectTestGenerationContextAsync( ProjectItemSummary selectedFile, string targetProjectNamespace, TestFramework testFramework, MockFramework mockFramework) { Microsoft.CodeAnalysis.Solution solution = CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace.CurrentSolution; DocumentId documentId = solution.GetDocumentIdsWithFilePath(selectedFile.FilePath).FirstOrDefault(); if (documentId == null) { throw new InvalidOperationException("Could not find document in solution with file path " + selectedFile.FilePath); } var document = solution.GetDocument(documentId); SyntaxNode root = await document.GetSyntaxRootAsync(); SemanticModel semanticModel = await document.GetSemanticModelAsync(); SyntaxNode firstClassDeclaration = root.DescendantNodes().FirstOrDefault(node => node.Kind() == SyntaxKind.ClassDeclaration); if (firstClassDeclaration == null) { throw new InvalidOperationException("Could not find class declaration."); } if (firstClassDeclaration.ChildTokens().Any(node => node.Kind() == SyntaxKind.AbstractKeyword)) { throw new InvalidOperationException("Cannot unit test an abstract class."); } SyntaxToken classIdentifierToken = firstClassDeclaration.ChildTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierToken); if (classIdentifierToken == default(SyntaxToken)) { throw new InvalidOperationException("Could not find class identifier."); } NamespaceDeclarationSyntax namespaceDeclarationSyntax = null; if (!TypeUtilities.TryGetParentSyntax(firstClassDeclaration, out namespaceDeclarationSyntax)) { throw new InvalidOperationException("Could not find class namespace."); } // Find property injection types var injectableProperties = new List <InjectableProperty>(); string classFullName = namespaceDeclarationSyntax.Name + "." + classIdentifierToken; INamedTypeSymbol classType = semanticModel.Compilation.GetTypeByMetadataName(classFullName); foreach (ISymbol member in classType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers())) { if (member.Kind == SymbolKind.Property) { IPropertySymbol property = (IPropertySymbol)member; foreach (AttributeData attribute in property.GetAttributes()) { if (PropertyInjectionAttributeNames.Contains(attribute.AttributeClass.ToString())) { var injectableProperty = InjectableProperty.TryCreateInjectableProperty(property.Name, property.Type.ToString(), mockFramework); if (injectableProperty != null) { injectableProperties.Add(injectableProperty); } } } } } string className = classIdentifierToken.ToString(); // Find constructor injection types List <InjectableType> constructorInjectionTypes = new List <InjectableType>(); SyntaxNode constructorDeclaration = firstClassDeclaration.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.ConstructorDeclaration); if (constructorDeclaration != null) { constructorInjectionTypes.AddRange( GetParameterListNodes(constructorDeclaration) .Select(node => InjectableType.TryCreateInjectableTypeFromParameterNode(node, semanticModel, mockFramework))); } // Find public method declarations IList <MethodDescriptor> methodDeclarations = new List <MethodDescriptor>(); foreach (MethodDeclarationSyntax methodDeclaration in firstClassDeclaration.ChildNodes().Where( n => n.Kind() == SyntaxKind.MethodDeclaration && ((MethodDeclarationSyntax)n).Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)))) { var parameterList = GetParameterListNodes(methodDeclaration).ToList(); var parameterTypes = GetArgumentDescriptors(parameterList, semanticModel, mockFramework); var isAsync = methodDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)) || DoesReturnTask(methodDeclaration); var hasReturnType = !DoesReturnNonGenericTask(methodDeclaration) && !DoesReturnVoid(methodDeclaration); methodDeclarations.Add(new MethodDescriptor(methodDeclaration.Identifier.Text, parameterTypes, isAsync, hasReturnType)); } string unitTestNamespace; string relativePath = this.GetRelativePath(selectedFile); if (string.IsNullOrEmpty(relativePath)) { unitTestNamespace = targetProjectNamespace; } else { List <string> defaultNamespaceParts = targetProjectNamespace.Split('.').ToList(); List <string> unitTestNamespaceParts = new List <string>(defaultNamespaceParts); unitTestNamespaceParts.AddRange(relativePath.Split('\\')); unitTestNamespace = string.Join(".", unitTestNamespaceParts); } List <InjectableType> injectedTypes = new List <InjectableType>(injectableProperties); injectedTypes.AddRange(constructorInjectionTypes.Where(t => t != null)); GenerateMockNames(injectedTypes); return(new TestGenerationContext( mockFramework, testFramework, document, unitTestNamespace, className, namespaceDeclarationSyntax.Name.ToString(), injectableProperties, constructorInjectionTypes, injectedTypes, methodDeclarations)); }
public static Document GetDocumentByFilePath(this Solution solution, string fullName) { return(solution.GetDocumentIdsWithFilePath(fullName) .Select(p => solution.GetDocument(p)) .FirstOrDefault()); }
private async Task <TestGenerationContext> CollectTestGenerationContextAsync( ProjectItemSummary selectedFile, string targetProjectNamespace, TestFramework testFramework, MockFramework mockFramework, IBoilerplateSettings settings) { Microsoft.CodeAnalysis.Solution solution = CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace.CurrentSolution; DocumentId documentId = solution.GetDocumentIdsWithFilePath(selectedFile.FilePath).FirstOrDefault(); if (documentId == null) { throw new InvalidOperationException("Could not find document in solution with file path " + selectedFile.FilePath); } var document = solution.GetDocument(documentId); SyntaxNode root = await document.GetSyntaxRootAsync(); SemanticModel semanticModel = await document.GetSemanticModelAsync(); SyntaxNode firstClassLikeDeclaration = root.DescendantNodes().FirstOrDefault(node => { var kind = node.Kind(); return(kind == SyntaxKind.ClassDeclaration || kind == SyntaxKind.StructDeclaration || kind == (SyntaxKind)9063); // record - Cannot update CodeAnalysis library because it's not found in VS 2019 }); if (firstClassLikeDeclaration == null) { throw new InvalidOperationException("Could not find class, struct or record declaration."); } if (firstClassLikeDeclaration.ChildTokens().Any(node => node.Kind() == SyntaxKind.AbstractKeyword)) { throw new InvalidOperationException("Cannot unit test an abstract class."); } SyntaxToken classIdentifierToken = firstClassLikeDeclaration.ChildTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierToken); if (classIdentifierToken == default(SyntaxToken)) { throw new InvalidOperationException("Could not find class identifier."); } object namespaceDeclarationSyntax = null; // 8842 is NamespaceDeclaration // 8845 is FileScopedNamespaceDeclaration // We would normally look for a node descended from BaseNamespaceDeclarationSyntax, but we don't have that type defined in the v1 Microsoft.CodeAnalysis DLL. // We can fix this once we are building against a higher version and can drop support for VS 2019. if (!TypeUtilities.TryGetParentSyntax(firstClassLikeDeclaration, (syntaxNode) => { return(syntaxNode.RawKind == 8842 || syntaxNode.RawKind == 8845); }, out namespaceDeclarationSyntax)) { throw new InvalidOperationException("Could not find class namespace."); } // Find property injection types var injectableProperties = new List <InjectableProperty>(); // We need to get the name via reflection since the DLL we are building against does not have the BaseNamespaceDeclarationSyntax or FileScopedNamespaceDeclarationSyntax types. string qualifiedNamespaceString = namespaceDeclarationSyntax.GetType().GetProperty("Name").GetValue(namespaceDeclarationSyntax, null).ToString(); string classFullName = qualifiedNamespaceString + "." + classIdentifierToken; INamedTypeSymbol classType = semanticModel.Compilation.GetTypeByMetadataName(classFullName); foreach (ISymbol member in classType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers())) { if (member.Kind == SymbolKind.Property) { IPropertySymbol property = (IPropertySymbol)member; foreach (AttributeData attribute in property.GetAttributes()) { if (PropertyInjectionAttributeNames.Contains(attribute.AttributeClass.ToString())) { var injectableProperty = InjectableProperty.TryCreateInjectableProperty(property.Name, property.Type.ToString(), mockFramework); if (injectableProperty != null) { injectableProperties.Add(injectableProperty); } } } } } string className = classIdentifierToken.ToString(); // Find constructor injection types List <InjectableType> constructorInjectionTypes = new List <InjectableType>(); SyntaxNode constructorDeclaration = firstClassLikeDeclaration.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.ConstructorDeclaration); if (constructorDeclaration != null) { constructorInjectionTypes.AddRange( GetParameterListNodes(constructorDeclaration) .Select(node => InjectableType.TryCreateInjectableTypeFromParameterNode(node, semanticModel, mockFramework))); } // Find public method declarations IList <MethodDescriptor> methodDeclarations = new List <MethodDescriptor>(); foreach (MethodDeclarationSyntax methodDeclaration in firstClassLikeDeclaration.ChildNodes().Where( n => n.Kind() == SyntaxKind.MethodDeclaration && ((MethodDeclarationSyntax)n).Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)))) { var parameterList = GetParameterListNodes(methodDeclaration).ToList(); var parameterTypes = GetArgumentDescriptors(parameterList, semanticModel, mockFramework); var attributeList = GetAttributeListNodes(methodDeclaration); var isAsync = methodDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)) || DoesReturnTask(methodDeclaration); var hasReturnType = !DoesReturnNonGenericTask(methodDeclaration) && !DoesReturnVoid(methodDeclaration); string returnType = methodDeclaration.ReturnType.ToFullString(); methodDeclarations.Add(new MethodDescriptor(methodDeclaration.Identifier.Text, parameterTypes, isAsync, hasReturnType, returnType, attributeList)); } string unitTestNamespace; string relativePath = this.GetRelativePath(selectedFile); if (string.IsNullOrEmpty(relativePath)) { unitTestNamespace = targetProjectNamespace; } else { List <string> defaultNamespaceParts = targetProjectNamespace.Split('.').ToList(); List <string> unitTestNamespaceParts = new List <string>(defaultNamespaceParts); unitTestNamespaceParts.AddRange(relativePath.Split('\\')); unitTestNamespace = string.Join(".", unitTestNamespaceParts); } List <InjectableType> injectedTypes = new List <InjectableType>(injectableProperties); injectedTypes.AddRange(constructorInjectionTypes.Where(t => t != null)); GenerateMockNames(injectedTypes); return(new TestGenerationContext( mockFramework, testFramework, document, settings, unitTestNamespace, className, qualifiedNamespaceString, injectableProperties, constructorInjectionTypes, injectedTypes, methodDeclarations)); }