public override async Task <CommandResult> ExecuteAsync(ProjectOrSolution projectOrSolution, CancellationToken cancellationToken = default) { AssemblyResolver.Register(); var codeAnalyzerOptions = new CodeAnalyzerOptions( ignoreAnalyzerReferences: Options.IgnoreAnalyzerReferences, ignoreCompilerDiagnostics: Options.IgnoreCompilerDiagnostics, reportNotConfigurable: Options.ReportNotConfigurable, reportSuppressedDiagnostics: Options.ReportSuppressedDiagnostics, logAnalyzerExecutionTime: Options.ExecutionTime, severityLevel: SeverityLevel, supportedDiagnosticIds: Options.SupportedDiagnostics, ignoredDiagnosticIds: Options.IgnoredDiagnostics, projectNames: Options.Projects, ignoredProjectNames: Options.IgnoredProjects, language: Language); IEnumerable <string> analyzerAssemblies = Options.AnalyzerAssemblies; if (Options.UseRoslynatorAnalyzers) { analyzerAssemblies = analyzerAssemblies.Concat(RoslynatorAnalyzersAssemblies); } CultureInfo culture = (Options.Culture != null) ? CultureInfo.GetCultureInfo(Options.Culture) : null; var codeAnalyzer = new CodeAnalyzer( analyzerAssemblies: AnalyzerAssemblyLoader.LoadFiles(analyzerAssemblies, loadFixers: false), formatProvider: culture, options: codeAnalyzerOptions); if (projectOrSolution.IsProject) { Project project = projectOrSolution.AsProject(); WriteLine($"Analyze '{project.Name}'", ConsoleColor.Cyan, Verbosity.Minimal); ProjectAnalysisResult result = await codeAnalyzer.AnalyzeProjectAsync(project, cancellationToken); if (Options.Output != null && result.Diagnostics.Any()) { DiagnosticXmlSerializer.Serialize(result, project, Options.Output, culture); } } else { Solution solution = projectOrSolution.AsSolution(); ImmutableArray <ProjectAnalysisResult> results = await codeAnalyzer.AnalyzeSolutionAsync(solution, cancellationToken); if (Options.Output != null && results.Any(f => f.Diagnostics.Any())) { DiagnosticXmlSerializer.Serialize(results, solution, Options.Output, culture); } } return(CommandResult.Success); }
public static StatelessProjectResponse Server_HandleStatelessCodeCompletionRequest(StatelessProjectRequest request) { // Convert web request model to internal analysis model ProjectAnalysisRequest analysisRequest = new ProjectAnalysisRequest(); analysisRequest.ProjectModel = ProjectModelConverters.FromDtoToModel(request.Project); if (request.CodeCompletionParameters != null) { analysisRequest.CodeCompletionParameters = new ProjectAnalysisCodeCompletionParameters() { CtrlSpace = request.CodeCompletionParameters.CtrlSpace, Offset = request.CodeCompletionParameters.Offset, FileId = request.CodeCompletionParameters.FileId, Line = request.CodeCompletionParameters.Line, Column = request.CodeCompletionParameters.Column }; } // Analyze! ProjectAnalysisResult analysisResult = NRefactoryUtils.RunFullProjectAnalysis(analysisRequest); // Convert analysis result model to web service model StatelessProjectResponse response = new StatelessProjectResponse(); if (analysisResult.CompletionOptions != null) { response.CompletionOptions = analysisResult.CompletionOptions .Select(CodeCompletionResultUtility.FromICompletionDataToFileCodeCompletionResult) .ToArray(); for (int i = 0, len = response.CompletionOptions.Length; i < len; i++) { response.CompletionOptions[i].Id = i; } response.CompletionWord = analysisResult.CompletionWord; if (analysisResult.BestMatchToCompletionWord != null) { response.BestMatchToCompletionWord = response.CompletionOptions.FirstOrDefault(x => x.CompletionText == analysisResult.BestMatchToCompletionWord.CompletionText); } } var allErrors = new List <FileParseResult>(); foreach (var fileModel in analysisRequest.ProjectModel.GetFileDescendants()) { allErrors.AddRange(fileModel.Parser.ErrorsAndWarnings .Select(x => new FileParseResult() { FileId = fileModel.Id, FileName = fileModel.Name, Line = x.Region.BeginLine, Column = x.Region.BeginColumn, Type = x.ErrorType, Message = x.Message }).ToArray()); } response.Errors = allErrors.ToArray(); response.MsElapsed = analysisResult.TimeElapsed.TotalMilliseconds; // string.Format("{0}", analysisResult.TimeElapsed.TotalMilliseconds); return(response); }
public static StatelessProjectResponse Server_HandleStatelessCodeCompletionRequest(StatelessProjectRequest request) { // Convert web request model to internal analysis model ProjectAnalysisRequest analysisRequest = new ProjectAnalysisRequest(); analysisRequest.ProjectModel = ProjectModelConverters.FromDtoToModel(request.Project); if (request.CodeCompletionParameters != null) { analysisRequest.CodeCompletionParameters = new ProjectAnalysisCodeCompletionParameters() { CtrlSpace = request.CodeCompletionParameters.CtrlSpace, Offset = request.CodeCompletionParameters.Offset, FileId = request.CodeCompletionParameters.FileId, Line = request.CodeCompletionParameters.Line, Column = request.CodeCompletionParameters.Column }; } // Analyze! ProjectAnalysisResult analysisResult = NRefactoryUtils.RunFullProjectAnalysis(analysisRequest); // Convert analysis result model to web service model StatelessProjectResponse response = new StatelessProjectResponse(); if (analysisResult.CompletionOptions != null) { response.CompletionOptions = analysisResult.CompletionOptions .Select(x => new FileCodeCompletionResult() { CompletionText = x.CompletionText, DisplayText = x.DisplayText, Description = x.Description, OverloadCount = x.OverloadedData.Count(), CompletionCategoryDisplayText = (x.CompletionCategory == null ? "" : x.CompletionCategory.DisplayText) }).ToArray(); response.CompletionWord = analysisResult.CompletionWord; } var allErrors = new List <FileParseResult>(); foreach (var fileModel in analysisRequest.ProjectModel.GetFileDescendants()) { allErrors.AddRange(fileModel.Parser.ErrorsAndWarnings .Select(x => new FileParseResult() { FileId = fileModel.Id, FileName = fileModel.Name, Line = x.Region.BeginLine, Column = x.Region.BeginColumn, Type = x.ErrorType, Message = x.Message }).ToArray()); } response.Errors = allErrors.ToArray(); response.TimeElapsed = string.Format("{0} ms", analysisResult.TimeElapsed.TotalMilliseconds); return(response); }
public static void Serialize( ProjectAnalysisResult result, Project project, string filePath, IFormatProvider formatProvider = null) { XElement summary = CreateSummary(result.GetAllDiagnostics(), formatProvider); XElement projectElement = SerializeProjectAnalysisResult(result, project, formatProvider); SerializeDocument(filePath, summary, projectElement); }
private static void GetDocumentContext(ProjectAnalysisResult result, int textCursorOffset, ReadOnlyDocument doc) { #region Debugging Aid // Resolve content around text cursor #if false int numberOfCharactersAroundCursorToResolve = 20; int firstCharOffset = textCursorOffset - numberOfCharactersAroundCursorToResolve / 2; int lastCharOffset = textCursorOffset + numberOfCharactersAroundCursorToResolve / 2; #else int firstCharOffset = textCursorOffset - 40; int lastCharOffset = textCursorOffset + 20; #endif // shift window to the "right" if (firstCharOffset < 0) { lastCharOffset -= firstCharOffset; firstCharOffset = 0; } // shift window to the "left" if (lastCharOffset > doc.TextLength) { firstCharOffset -= (lastCharOffset - doc.TextLength); lastCharOffset = doc.TextLength; // compensate, in case "left" side of window is in the void if (firstCharOffset < 0) { firstCharOffset = 0; } } //if (doc.TextLength < firstCharOffset + numberOfCharactersAroundCursorToResolve) // numberOfCharactersAroundCursorToResolve = doc.TextLength - firstCharOffset; //string surroundingText = doc.GetText(firstCharOffset, numberOfCharactersAroundCursorToResolve); //Debug.WriteLine("Text around cursor: [{0}]", surroundingText); result.CompletionContextBefore = doc.GetText(firstCharOffset, textCursorOffset - firstCharOffset); result.CompletionContextAfter = doc.GetText(textCursorOffset, lastCharOffset - textCursorOffset); Debug.WriteLine("Completion Context: \"{0}\" <cursor> \"{1}\"", result.CompletionContextBefore, result.CompletionContextAfter); #endregion }
private static XElement SerializeProjectAnalysisResult( ProjectAnalysisResult result, Project project, IFormatProvider formatProvider) { return(new XElement( "Project", new XAttribute("Name", project.Name), new XAttribute("FilePath", project.FilePath), new XElement("Diagnostics", result.Diagnostics .OrderBy(f => f.Location.SourceTree?.FilePath) .ThenBy(f => f.Id) .ThenBy(f => f.Location.SourceSpan.Start) .Select(f => SerializeDiagnostic(f, formatProvider)) ) )); }
private static XElement SerializeProjectAnalysisResult( ProjectAnalysisResult result, IFormatProvider formatProvider) { return(new XElement( "Project", new XAttribute("Name", result.Project.Name), new XAttribute("FilePath", result.Project.FilePath), new XElement( "Diagnostics", result.Diagnostics .OrderBy(f => f.LineSpan.Path) .ThenBy(f => f.Descriptor.Id) .ThenBy(f => f.LineSpan.StartLinePosition.Line) .ThenBy(f => f.LineSpan.StartLinePosition.Character) .Select(f => SerializeDiagnostic(f, formatProvider)) ) )); }
public void SetUp() { var solutionDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "TestXml", "TestPorting"); _tmpDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "TestXml", "TmpDirectory"); DirectoryCopy(solutionDirectory, _tmpDirectory, true); _tmpSolutionDirectory = Path.Combine(_tmpDirectory, "src"); _tmpSolutionFileName = Path.Combine(_tmpSolutionDirectory, "NopCommerce.sln"); _tmpProjectPath = Path.Combine(_tmpSolutionDirectory, "Libraries", "Nop.Core", "Nop.Core.csproj"); _apiAnalysisHandlerMock.Reset(); _apiAnalysisHandlerMock.Setup(analyzer => analyzer.AnalyzeSolution(It.IsAny <string>(), It.IsAny <List <string> >(), It.IsAny <string>())) .Returns((string solutionFilePath, List <string> projects, string targetFramework) => { return(Task.Run(() => projects.Select(project => { var package = new PackageVersionPair { PackageId = "Newtonsoft.Json", Version = "11.0.1" }; var packageAnalysisResult = Task.Run(() => new PackageAnalysisResult { PackageVersionPair = package, CompatibilityResults = new Dictionary <string, CompatibilityResult> { { targetFramework, new CompatibilityResult { Compatibility = Compatibility.COMPATIBLE, CompatibleVersions = new List <string> { "12.0.3", "12.0.4" } } } }, Recommendations = new PortingAssistant.Client.Model.Recommendations { RecommendedActions = new List <RecommendedAction> { new RecommendedAction { RecommendedActionType = RecommendedActionType.UpgradePackage, Description = "12.0.3" } } } }); var projectAnalysisResult = new ProjectAnalysisResult { ProjectName = Path.GetFileNameWithoutExtension(project), ProjectFilePath = project, PackageAnalysisResults = new Dictionary <PackageVersionPair, Task <PackageAnalysisResult> > { { package, packageAnalysisResult } }, SourceFileAnalysisResults = new List <SourceFileAnalysisResult> { _sourceFileAnalysisResult }, ProjectGuid = "xxx", ProjectType = nameof(SolutionProjectType.KnownToBeMSBuildFormat), PreportMetaReferences = new List <string> { }, MetaReferences = new List <string> { }, ExternalReferences = null, ProjectRules = null }; return new KeyValuePair <string, ProjectAnalysisResult>(project, projectAnalysisResult); }).ToDictionary(k => k.Key, v => v.Value))); }); _apiAnalysisHandlerMock.Setup(analyzer => analyzer.AnalyzeSolutionIncremental(It.IsAny <string>(), It.IsAny <List <string> >(), It.IsAny <string>())) .Returns((string solutionFilePath, List <string> projects, string targetFramework) => { return(Task.Run(() => { return projects.Select(project => { var package = new PackageVersionPair { PackageId = "Newtonsoft.Json", Version = "11.0.1" }; var packageAnalysisResult = Task.Run(() => new PackageAnalysisResult { PackageVersionPair = package, CompatibilityResults = new Dictionary <string, CompatibilityResult> { { targetFramework, new CompatibilityResult { Compatibility = Compatibility.COMPATIBLE, CompatibleVersions = new List <string> { "12.0.3", "12.0.4" } } } }, Recommendations = new PortingAssistant.Client.Model.Recommendations { RecommendedActions = new List <RecommendedAction> { new RecommendedAction { RecommendedActionType = RecommendedActionType.UpgradePackage, Description = "12.0.3" } } } }); var projectAnalysisResult = new ProjectAnalysisResult { ProjectName = Path.GetFileNameWithoutExtension(project), ProjectFilePath = project, PackageAnalysisResults = new Dictionary <PackageVersionPair, Task <PackageAnalysisResult> > { { package, packageAnalysisResult } }, SourceFileAnalysisResults = new List <SourceFileAnalysisResult> { _sourceFileAnalysisResult }, ProjectGuid = "xxx", ProjectType = nameof(SolutionProjectType.KnownToBeMSBuildFormat) }; return new KeyValuePair <string, ProjectAnalysisResult>(project, projectAnalysisResult); }).ToDictionary(k => k.Key, v => v.Value); })); }); _apiAnalysisHandlerMock.Setup(analyzer => analyzer.AnalyzeFileIncremental(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <List <string> >(), It.IsAny <List <string> >(), It.IsAny <RootNodes>(), It.IsAny <Codelyzer.Analysis.Model.ExternalReferences>(), It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <string>())) .Returns((string filePath, string project, string solutionPath, List <string> preportReferences, List <string> metaReferences, RootNodes projectRules, Codelyzer.Analysis.Model.ExternalReferences externalReferences, bool actionsOnly, bool compatibleOnly, string targetFramework) => { return(Task.Run(() => { return new List <SourceFileAnalysisResult> { _sourceFileAnalysisResult }; })); }); _apiAnalysisHandlerMock.Setup(analyzer => analyzer.AnalyzeFileIncremental(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <List <string> >(), It.IsAny <List <string> >(), It.IsAny <RootNodes>(), It.IsAny <Codelyzer.Analysis.Model.ExternalReferences>(), It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <string>())) .Returns((string filePath, string fileContents, string project, string solutionPath, List <string> preportReferences, List <string> metaReferences, RootNodes projectRules, Codelyzer.Analysis.Model.ExternalReferences externalReferences, bool actionsOnly, bool compatibleOnly, string targetFramework) => { return(Task.Run(() => { return new List <SourceFileAnalysisResult> { _sourceFileAnalysisResult }; })); }); }
public void SetUp() { var solutionDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "TestXml", "TestPorting"); _tmpDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "TestXml", "TmpDirectory"); DirectoryCopy(solutionDirectory, _tmpDirectory, true); _tmpSolutionDirectory = Path.Combine(_tmpDirectory, "src"); _tmpProjectPath = Path.Combine(_tmpSolutionDirectory, "Libraries", "Nop.Core", "Nop.Core.csproj"); _apiAnalysisHandlerMock.Reset(); _apiAnalysisHandlerMock.Setup(analyzer => analyzer.AnalyzeSolution(It.IsAny <string>(), It.IsAny <List <string> >())) .Returns((string solutionFilePath, List <string> projects) => { return(Task.Run(() => projects.Select(project => { var package = new PackageVersionPair { PackageId = "Newtonsoft.Json", Version = "11.0.1" }; var packageAnalysisResult = Task.Run(() => new PackageAnalysisResult { PackageVersionPair = package, CompatibilityResults = new Dictionary <string, CompatibilityResult> { { "netcoreapp3.1", new CompatibilityResult { Compatibility = Compatibility.COMPATIBLE, CompatibleVersions = new List <string> { "12.0.3", "12.0.4" } } } }, Recommendations = new Recommendations { RecommendedActions = new List <RecommendedAction> { new RecommendedAction { RecommendedActionType = RecommendedActionType.UpgradePackage, Description = "12.0.3" } } } }); var projectAnalysisResult = new ProjectAnalysisResult { ProjectName = Path.GetFileNameWithoutExtension(project), ProjectFilePath = project, PackageAnalysisResults = new Dictionary <PackageVersionPair, Task <PackageAnalysisResult> > { { package, packageAnalysisResult } }, SourceFileAnalysisResults = new List <SourceFileAnalysisResult> { _sourceFileAnalysisResult }, ProjectGuid = "xxx", ProjectType = SolutionProjectType.KnownToBeMSBuildFormat.ToString() }; return new KeyValuePair <string, ProjectAnalysisResult>(project, projectAnalysisResult); }).ToDictionary(k => k.Key, v => v.Value))); }); }
public static ProjectAnalysisResult RunFullProjectAnalysis(ProjectAnalysisRequest projectAnalysisRequest) // ProjectModel projectModel, int fileId, int line, int column) { Stopwatch sw = Stopwatch.StartNew(); ProjectAnalysisResult projectAnalysisResult = new ProjectAnalysisResult(); ProjectModel projectModel = projectAnalysisRequest.ProjectModel; // Set up the project (if not already done) if (projectModel.ProjectContent == null) { projectModel.ProjectContent = new CSharpProjectContent(); projectModel.ProjectContent = projectModel.ProjectContent.AddAssemblyReferences(QCReferences.Value); } // For each new file, we need to integrate it into the project content var fileModelsInProject = projectModel.GetFileDescendants().ToArray(); foreach (var fileModelInProject in fileModelsInProject) { IntegrateFileModel(projectModel, fileModelInProject); } // We can return now if no code completion was requested if (projectAnalysisRequest.CodeCompletionParameters == null) { projectAnalysisResult.TimeElapsed = sw.Elapsed; return projectAnalysisResult; } // Now it's time to give attention specifically to the matter of resolving the code completion // options. This, of course, requires a deeper analysis of the specified file... var codeCompletionParams = projectAnalysisRequest.CodeCompletionParameters; // Locate the file in the project ProjectFileModel fileModel = projectModel.FindFile(codeCompletionParams.FileId); if (fileModel == null) throw new Exception("Specified file does not exist in this project"); // Create a TypeSystem.ICompilation that allows resolving within the project. var compilation = projectModel.ProjectContent.CreateCompilation(); #region Resolve text cursor/caret location // The text cursor position is crucial to creating a properly-scoped type resolution context // so as to get relevant code completion suggestions. int textCursorOffset; TextLocation textCursorLocation; ReadOnlyDocument doc = new ReadOnlyDocument(fileModel.Content); if (codeCompletionParams.Line == 0 && codeCompletionParams.Column == 0) { textCursorOffset = codeCompletionParams.Offset; textCursorLocation = doc.GetLocation(textCursorOffset); codeCompletionParams.Line = textCursorLocation.Line; codeCompletionParams.Column = textCursorLocation.Column; } else { textCursorLocation = new TextLocation(codeCompletionParams.Line, codeCompletionParams.Column); textCursorOffset = doc.GetOffset(textCursorLocation); codeCompletionParams.Offset = textCursorOffset; } #endregion #region Create and Refine the type resolution context as much as possible based upon the cursor position var typeResolveContext = new CSharpTypeResolveContext(compilation.MainAssembly); // Constrain the resolve context by using scope typeResolveContext = typeResolveContext .WithUsingScope(fileModel.UnresolvedFile.GetUsingScope(textCursorLocation) .Resolve(compilation)); var curDef = fileModel.UnresolvedFile.GetInnermostTypeDefinition(textCursorLocation); if (curDef != null) { var resolvedDef = curDef.Resolve(typeResolveContext).GetDefinition(); typeResolveContext = typeResolveContext.WithCurrentTypeDefinition(resolvedDef); var curMember = resolvedDef.Members.FirstOrDefault(m => m.Region.Begin <= textCursorLocation && textCursorLocation < m.BodyRegion.End); if (curMember != null) { typeResolveContext = typeResolveContext.WithCurrentMember(curMember); } } #endregion // The purpose of the rest of these steps is a little fuzzy in my mind... // I'm still trying to understand them fully and if/why they're all needed. // It seems there is some redundancy here... var completionContext = new DefaultCompletionContextProvider(doc, fileModel.UnresolvedFile); #region Add Preprocessor Symbols?? completionContext.AddSymbol("TEST"); foreach (var sym in fileModel.SyntaxTree.ConditionalSymbols) completionContext.AddSymbol(sym); #endregion var completionDataFactory = new TestCompletionDataFactory(new CSharpResolver(typeResolveContext)); var completionEngine = new CSharpCompletionEngine(doc, completionContext, completionDataFactory, projectModel.ProjectContent, typeResolveContext); completionEngine.EolMarker = Environment.NewLine; completionEngine.FormattingPolicy = FormattingOptionsFactory.CreateMono(); projectModel.CompletionEngine = completionEngine; #region Debugging Aid // Resolve content around text cursor int numberOfCharactersAroundCursorToResolve = 20; int firstCharOffset = textCursorOffset - numberOfCharactersAroundCursorToResolve/2; if (firstCharOffset < 0) firstCharOffset = 0; if (doc.TextLength < firstCharOffset+numberOfCharactersAroundCursorToResolve) numberOfCharactersAroundCursorToResolve = doc.TextLength - firstCharOffset; string surroundingText = doc.GetText(firstCharOffset, numberOfCharactersAroundCursorToResolve); Debug.WriteLine("Text around cursor: [{0}]", surroundingText); #endregion // Finally, generate completion data! var completionOptions = completionEngine.GetCompletionData(textCursorOffset, projectAnalysisRequest.CodeCompletionParameters.CtrlSpace).ToArray(); projectAnalysisResult.CompletionOptions = completionEngine.GetCompletionData(textCursorOffset, projectAnalysisRequest.CodeCompletionParameters.CtrlSpace).ToArray(); projectAnalysisResult.AutoCompleteEmptyMatch = completionEngine.AutoCompleteEmptyMatch; projectAnalysisResult.AutoSelect = completionEngine.AutoSelect; projectAnalysisResult.DefaultCompletionString = completionEngine.DefaultCompletionString; int startPos, wordLength; if (completionEngine.TryGetCompletionWord(textCursorOffset, out startPos, out wordLength)) { Debug.WriteLine("TryGetCompletionWord :: startpos:{0} wordlength:{1}", startPos, wordLength); projectAnalysisResult.CompletionWord = doc.GetText(startPos, wordLength); } projectAnalysisResult.TimeElapsed = sw.Elapsed; return projectAnalysisResult; }
public static FileOperationResponse DoAutoComplete(FileOperationRequest request) { FileOperationResponse response = new FileOperationResponse(); ProjectModel projectModel = null; Stopwatch sw = Stopwatch.StartNew(); try { var projectModelRepo = EndpointHost.AppHost.TryResolve <IProjectModelRepository>(); projectModel = projectModelRepo.GetProject(request.UserId, request.ProjectId); var analysisRequest = new ProjectAnalysisRequest() { ProjectModel = projectModel, CodeCompletionParameters = new ProjectAnalysisCodeCompletionParameters() { FileId = request.FileId, Line = request.CompleteCode.LineNumber, Column = request.CompleteCode.ColumnNumber, Offset = request.CompleteCode.Offset, CtrlSpace = request.CompleteCode.CtrlSpace } }; // Analyze! ProjectAnalysisResult analysisResult = NRefactoryUtils.RunFullProjectAnalysis(analysisRequest); // Convert analysis result model to file operation response DTO if (analysisResult.CompletionOptions != null) { var codeCompletion = response.CodeCompletion = new FileCodeCompletionResponse(); codeCompletion.CompletionOptions = analysisResult.CompletionOptions .Select(CodeCompletionResultUtility.FromICompletionDataToFileCodeCompletionResult).ToArray(); for (int i = 0, len = codeCompletion.CompletionOptions.Length; i < len; i++) { codeCompletion.CompletionOptions[i].Id = i; } codeCompletion.CompletionWord = analysisResult.CompletionWord; if (analysisResult.BestMatchToCompletionWord != null) { codeCompletion.BestMatchToCompletionWord = codeCompletion.CompletionOptions.FirstOrDefault(x => x.CompletionText == analysisResult.BestMatchToCompletionWord.CompletionText); } // Record text around cursor codeCompletion.TextBeforeCursor = analysisResult.CompletionContextBefore; codeCompletion.TextAfterCursor = analysisResult.CompletionContextAfter; // Record inputs codeCompletion.Line = analysisResult.Line; codeCompletion.Column = analysisResult.Column; codeCompletion.Offset = analysisResult.Offset; } var allErrors = new List <FileParseResult>(); foreach (var fileModel in analysisRequest.ProjectModel.GetFileDescendants()) { allErrors.AddRange(fileModel.Parser.ErrorsAndWarnings .Select(x => new FileParseResult() { FileId = fileModel.Id, FileName = fileModel.Name, Line = x.Region.BeginLine, Column = x.Region.BeginColumn, Type = x.ErrorType, Message = x.Message }).ToArray()); } response.ParseResults = allErrors.ToArray(); /* * StatelessProjectResponse response = new StatelessProjectResponse(); * if (analysisResult.CompletionOptions != null) * { * response.CompletionOptions = analysisResult.CompletionOptions * .Select(x => new FileCodeCompletionResult() * { * CompletionText = x.CompletionText, * DisplayText = x.DisplayText, * Description = x.Description, * OverloadCount = x.OverloadedData.Count(), * CompletionCategoryDisplayText = (x.CompletionCategory == null ? "" : x.CompletionCategory.DisplayText) * }).ToArray(); * response.CompletionWord = analysisResult.CompletionWord; * if (analysisResult.BestMatchToCompletionWord != null) * response.BestMatchToCompletionWord = response.CompletionOptions.FirstOrDefault(x => x.CompletionText == analysisResult.BestMatchToCompletionWord.CompletionText); * } * var allErrors = new List<FileParseResult>(); * foreach (var fileModel in analysisRequest.ProjectModel.GetFileDescendants()) * { * allErrors.AddRange(fileModel.Parser.ErrorsAndWarnings * .Select(x => new FileParseResult() * { * FileId = fileModel.Id, * FileName = fileModel.Name, * Line = x.Region.BeginLine, * Column = x.Region.BeginColumn, * Type = x.ErrorType, * Message = x.Message * }).ToArray()); * } * response.Errors = allErrors.ToArray(); * response.MsElapsed = analysisResult.TimeElapsed.TotalMilliseconds; // string.Format("{0} ms", analysisResult.TimeElapsed.TotalMilliseconds); */ response.Status.Success = true; } catch (Exception ex) { log.Error(ex.ToString(), ex); response.Status.SetError(ex); } finally { //response.CodeCompletion.MsElapsed = analysisResult.TimeElapsed.TotalMilliseconds; // string.Format("{0} ms", analysisResult.TimeElapsed.TotalMilliseconds); response.Status.MsElapsed = sw.ElapsedMilliseconds; } return(response); }
//private void ParseFile(ProjectFileViewModel fileViewModelToParse) //{ // var fileDto = ProjectMVVMConverters.FromViewModelToModel(fileViewModelToParse); // MockWebServiceUtility.ParseFile(fileDto, response => // { // if (response.Parse == null) // return; // var errors = response.Parse.Errors; // //response.Parse.Errors // if (errors != null) // { // Logger.AppendLine("{0} error(s) detected.", errors.Length); // if (errors.Length > 0) // foreach (var err in errors) // Logger.AppendLine("{0}: In file {1} ({2}, {3}): {4}", err.Type, err.FileName, err.Line, err.Column, err.Message); // } // }); //} //private static FileOperationResponse DoAutoComplete(FileOperationRequest request) //{ // return AutocompleteServiceUtil.DoAutoComplete(request); //} private void AnalyzeProject2(bool ctrlSpace) { //ctrlSpace = true; var sw = Stopwatch.StartNew(); var projectVm = (ProjectViewModel)DataContext; var fileVm = projectVm.SelectedProjectItem as ProjectFileViewModel; if (fileVm == null) { Logger.AppendLine("A file must be selected"); return; } fileVm.CaretIndex = SelectedFileContent.CaretIndex; // Synchronize the view's content with the viewmodel (since by default this is only done AFTER the textbox loses focus) fileVm.Content = SelectedFileContent.Text; // update file content in local data store if not already done var projectModelRepo = EndpointHost.AppHost.TryResolve <IProjectModelRepository>(); projectModelRepo.SaveFileContent(478, fileVm.ProjectId, fileVm.Id, fileVm.Content); var fileRequest = new FileOperationRequest() { UserId = 478, //projectVm..UserId, ProjectId = projectVm.ProjectId, FileId = fileVm.Id, CompleteCode = new FileCodeCompletionRequest() { AutoComplete = true, Offset = fileVm.CaretIndex, LineNumber = fileVm.CaretLine, ColumnNumber = fileVm.CaretColumn, CtrlSpace = ctrlSpace }, Parse = new FileParseRequest() }; var fileResponse = AutocompleteServiceUtil.DoAutoComplete(fileRequest); #if false var projectDto = ProjectMVVMConverters.FromViewModelToModel(projectVm); var projectModel = ProjectModelConverters.FromDtoToModel(projectDto); var analysisRequest = new ProjectAnalysisRequest() { ProjectModel = projectModel, CodeCompletionParameters = new ProjectAnalysisCodeCompletionParameters() { CtrlSpace = ctrlSpace, FileId = fileVm.Id, Offset = fileVm.CaretIndex //Line = request.CompleteCode.LineNumber, //Column = request.CompleteCode.ColumnNumber, //CtrlSpace = true // always true for now } }; ProjectAnalysisResult analysisResult = NRefactoryUtils.RunFullProjectAnalysis(analysisRequest); //StatelessProjectResponse response = MockWebServiceUtility.Server_HandleStatelessCodeCompletionRequest(request); FileOperationResponse response = new FileOperationResponse(); // Convert analysis result model to file operation response DTO if (analysisResult.CompletionOptions != null) { response.CodeCompletion = new FileCodeCompletionResponse(); response.CodeCompletion.CompletionOptions = analysisResult.CompletionOptions .Select(ProjectModelConverters.FromICompletionDataToFileCodeCompletionResult).ToArray(); for (int i = 0, len = response.CodeCompletion.CompletionOptions.Length; i < len; i++) { response.CodeCompletion.CompletionOptions[i].Id = i; } response.CodeCompletion.CompletionWord = analysisResult.CompletionWord; if (analysisResult.BestMatchToCompletionWord != null) { response.CodeCompletion.BestMatchToCompletionWord = response.CodeCompletion.CompletionOptions.FirstOrDefault(x => x.CompletionText == analysisResult.BestMatchToCompletionWord.CompletionText); } } var allErrors = new List <FileParseResult>(); foreach (var fileModel in analysisRequest.ProjectModel.GetFileDescendants()) { allErrors.AddRange(fileModel.Parser.ErrorsAndWarnings .Select(x => new FileParseResult() { FileId = fileModel.Id, FileName = fileModel.Name, Line = x.Region.BeginLine, Column = x.Region.BeginColumn, Type = x.ErrorType, Message = x.Message }).ToArray()); } response.ParseResults = allErrors.ToArray(); #endif //var jsonResponse = JsonConvert.SerializeObject(fileResponse, Formatting.Indented); //Logger.AppendLine(jsonResponse); // Summarize results... Logger.AppendLine("========================================================="); Logger.AppendLine("Project analysis completed in {0} ms", sw.ElapsedMilliseconds); if (fileResponse.CodeCompletion == null) { Logger.AppendLine("No Completion Results."); Logger.SetCodeCompletionOptions(null, null); } else { var codeCompletion = fileResponse.CodeCompletion; Logger.SetCodeCompletionOptions(codeCompletion.CompletionOptions, codeCompletion.BestMatchToCompletionWord); Logger.AppendLine("Completion Results..."); Logger.AppendLine(" Input: Line:{0} Col:{1} Offset:{2}", codeCompletion.Line, codeCompletion.Column, codeCompletion.Offset); Logger.AppendLine(" Context: \"{0}\" <cursor> \"{1}\"", codeCompletion.TextBeforeCursor, codeCompletion.TextAfterCursor); Logger.AppendLine(" {0} code completion option(s) generated.", codeCompletion.CompletionOptions.Length); // Try to find closest matching completion result if (string.IsNullOrWhiteSpace(codeCompletion.CompletionWord)) { Logger.AppendLine(" No code completion word detected."); } else { if (codeCompletion.BestMatchToCompletionWord != null) { Logger.AppendLine(" Detected code completion word, \"{0}\", most closely matches completion option \"{1}\".", codeCompletion.CompletionWord, codeCompletion.BestMatchToCompletionWord.CompletionText); } else { Logger.AppendLine(" Detected code completion word: {0}", codeCompletion.CompletionWord); } } } if (fileResponse.ParseResults != null) { Logger.AppendLine("{0} error(s) detected.", fileResponse.ParseResults.Length); if (fileResponse.ParseResults.Length > 0) { foreach (var err in fileResponse.ParseResults) { Logger.AppendLine("{0}: In file {1} ({2}, {3}): {4}", err.Type, err.FileName, err.Line, err.Column, err.Message); } } } }
//// todo: eliminate this method later //private static void AugmentProjectModelWithAlgorithmBase(ProjectModel model) //{ // model.Children.Add(QcAlgorithmFileModel.Value); //} public static ProjectAnalysisResult RunFullProjectAnalysis(ProjectAnalysisRequest projectAnalysisRequest) { Stopwatch sw = Stopwatch.StartNew(); ProjectAnalysisResult projectAnalysisResult = new ProjectAnalysisResult(); ProjectModel projectModel = projectAnalysisRequest.ProjectModel; // todo: Ask Jared why QCAlgorithm is a partial class and why it's not included in "common" #if false // ************************************************************************************ // NOTE: In order to get this project building cleanly, with minimal dependencies // before checking into Github, I've removed all hard QuantConnect dependencies, // including the QCAlgorithm.cs embedded resource and the assembly references to // QuantConnect.Algorithm.Interface // Augment the project model with the QCAgorithm base class // projectModel.Children.Add(QcAlgorithmFileModel.Value); // ************************************************************************************ #endif // Set up the project (if not already done) if (projectModel.ProjectContent == null) { projectModel.ProjectContent = new CSharpProjectContent(); projectModel.ProjectContent = projectModel.ProjectContent.AddAssemblyReferences(QCReferences.Value); } // For each new file, we need to integrate it into the project content var fileModelsInProject = projectModel.GetFileDescendants().ToArray(); foreach (var fileModelInProject in fileModelsInProject) { IntegrateFileModel(projectModel, fileModelInProject); } // We can return now if no code completion was requested if (projectAnalysisRequest.CodeCompletionParameters == null) { projectAnalysisResult.TimeElapsed = sw.Elapsed; return(projectAnalysisResult); } // Now it's time to give attention specifically to the matter of resolving the code completion // options. This, of course, requires a deeper analysis of the specified file... var codeCompletionParams = projectAnalysisRequest.CodeCompletionParameters; // Locate the file in the project ProjectFileModel fileModel = projectModel.FindFile(codeCompletionParams.FileId); if (fileModel == null) { throw new Exception("Specified file does not exist in this project"); } // Create a TypeSystem.ICompilation that allows resolving within the project. var compilation = projectModel.ProjectContent.CreateCompilation(); #region Resolve text cursor/caret location // The text cursor position is crucial to creating a properly-scoped type resolution context // so as to get relevant code completion suggestions. int textCursorOffset = 0; TextLocation textCursorLocation = new TextLocation(1, 1); ReadOnlyDocument doc = new ReadOnlyDocument(fileModel.Content); try { // if line and column aren't set, we'll assume that the cursor offset/index is set if (codeCompletionParams.Line == 0 && codeCompletionParams.Column == 0) { textCursorOffset = codeCompletionParams.Offset; if (textCursorOffset < 0) { textCursorOffset = 0; } textCursorLocation = doc.GetLocation(textCursorOffset); } // if either line or column are invalid (i.e. <= 0), then we'll use offset 0 instead else if (codeCompletionParams.Line <= 0 || codeCompletionParams.Column <= 0) { textCursorOffset = 0; } else { textCursorLocation = new TextLocation(codeCompletionParams.Line, codeCompletionParams.Column); textCursorOffset = doc.GetOffset(textCursorLocation); codeCompletionParams.Offset = textCursorOffset; } } catch (Exception) { textCursorOffset = 0; textCursorLocation = new TextLocation(1, 1); } finally { projectAnalysisResult.Line = textCursorLocation.Line; projectAnalysisResult.Column = textCursorLocation.Column; projectAnalysisResult.Offset = textCursorOffset; } #endregion #region Create and Refine the type resolution context as much as possible based upon the cursor position var typeResolveContext = new CSharpTypeResolveContext(compilation.MainAssembly); // Constrain the resolve context by using scope typeResolveContext = typeResolveContext .WithUsingScope(fileModel.UnresolvedFile.GetUsingScope(textCursorLocation) .Resolve(compilation)); var curDef = fileModel.UnresolvedFile.GetInnermostTypeDefinition(textCursorLocation); if (curDef != null) { var resolvedDef = curDef.Resolve(typeResolveContext).GetDefinition(); typeResolveContext = typeResolveContext.WithCurrentTypeDefinition(resolvedDef); var curMember = resolvedDef.Members.FirstOrDefault(m => m.Region.Begin <= textCursorLocation && textCursorLocation < m.BodyRegion.End); if (curMember != null) { typeResolveContext = typeResolveContext.WithCurrentMember(curMember); } } #endregion // The purpose of the rest of these steps is a little fuzzy in my mind... // I'm still trying to understand them fully and if/why they're all needed. // It seems there is some redundancy here... var completionContext = new DefaultCompletionContextProvider(doc, fileModel.UnresolvedFile); #region Add Preprocessor Symbols?? completionContext.AddSymbol("TEST"); foreach (var sym in fileModel.SyntaxTree.ConditionalSymbols) { completionContext.AddSymbol(sym); } #endregion var completionDataFactory = new CodeCompletionDataFactory(new CSharpResolver(typeResolveContext)); var completionEngine = new CSharpCompletionEngine(doc, completionContext, completionDataFactory, projectModel.ProjectContent, typeResolveContext); completionEngine.EolMarker = Environment.NewLine; completionEngine.FormattingPolicy = FormattingOptionsFactory.CreateMono(); projectModel.CompletionEngine = completionEngine; // Attach contextual info to analysis result GetDocumentContext(projectAnalysisResult, textCursorOffset, doc); // Finally, generate completion data! var completionOptions = completionEngine.GetCompletionData(textCursorOffset, projectAnalysisRequest.CodeCompletionParameters.CtrlSpace).ToArray(); projectAnalysisResult.CompletionOptions = completionOptions.OrderBy(x => x.CompletionText).ToArray(); projectAnalysisResult.AutoCompleteEmptyMatch = completionEngine.AutoCompleteEmptyMatch; projectAnalysisResult.AutoSelect = completionEngine.AutoSelect; projectAnalysisResult.DefaultCompletionString = completionEngine.DefaultCompletionString; int startPos, wordLength; if (completionEngine.TryGetCompletionWord(textCursorOffset, out startPos, out wordLength)) { //Debug.WriteLine("TryGetCompletionWord :: startpos:{0} wordlength:{1}", startPos, wordLength); string completionWord = projectAnalysisResult.CompletionWord = doc.GetText(startPos, wordLength); if (!string.IsNullOrWhiteSpace(completionWord)) { var bestMatch = projectAnalysisResult.CompletionOptions .FirstOrDefault(x => x.CompletionText.CompareTo(completionWord) >= 0); projectAnalysisResult.BestMatchToCompletionWord = bestMatch; //if (bestMatch != null) //projectAnalysisResult.BestMatchToCompletionWord = bestMatch.CompletionText; } } projectAnalysisResult.TimeElapsed = sw.Elapsed; return(projectAnalysisResult); }
public static ProjectAnalysisResult RunFullProjectAnalysis(ProjectAnalysisRequest projectAnalysisRequest) // ProjectModel projectModel, int fileId, int line, int column) { Stopwatch sw = Stopwatch.StartNew(); ProjectAnalysisResult projectAnalysisResult = new ProjectAnalysisResult(); ProjectModel projectModel = projectAnalysisRequest.ProjectModel; // Set up the project (if not already done) if (projectModel.ProjectContent == null) { projectModel.ProjectContent = new CSharpProjectContent(); projectModel.ProjectContent = projectModel.ProjectContent.AddAssemblyReferences(QCReferences.Value); } // For each new file, we need to integrate it into the project content var fileModelsInProject = projectModel.GetFileDescendants().ToArray(); foreach (var fileModelInProject in fileModelsInProject) { IntegrateFileModel(projectModel, fileModelInProject); } // We can return now if no code completion was requested if (projectAnalysisRequest.CodeCompletionParameters == null) { projectAnalysisResult.TimeElapsed = sw.Elapsed; return(projectAnalysisResult); } // Now it's time to give attention specifically to the matter of resolving the code completion // options. This, of course, requires a deeper analysis of the specified file... var codeCompletionParams = projectAnalysisRequest.CodeCompletionParameters; // Locate the file in the project ProjectFileModel fileModel = projectModel.FindFile(codeCompletionParams.FileId); if (fileModel == null) { throw new Exception("Specified file does not exist in this project"); } // Create a TypeSystem.ICompilation that allows resolving within the project. var compilation = projectModel.ProjectContent.CreateCompilation(); #region Resolve text cursor/caret location // The text cursor position is crucial to creating a properly-scoped type resolution context // so as to get relevant code completion suggestions. int textCursorOffset; TextLocation textCursorLocation; ReadOnlyDocument doc = new ReadOnlyDocument(fileModel.Content); if (codeCompletionParams.Line == 0 && codeCompletionParams.Column == 0) { textCursorOffset = codeCompletionParams.Offset; textCursorLocation = doc.GetLocation(textCursorOffset); codeCompletionParams.Line = textCursorLocation.Line; codeCompletionParams.Column = textCursorLocation.Column; } else { textCursorLocation = new TextLocation(codeCompletionParams.Line, codeCompletionParams.Column); textCursorOffset = doc.GetOffset(textCursorLocation); codeCompletionParams.Offset = textCursorOffset; } #endregion #region Create and Refine the type resolution context as much as possible based upon the cursor position var typeResolveContext = new CSharpTypeResolveContext(compilation.MainAssembly); // Constrain the resolve context by using scope typeResolveContext = typeResolveContext .WithUsingScope(fileModel.UnresolvedFile.GetUsingScope(textCursorLocation) .Resolve(compilation)); var curDef = fileModel.UnresolvedFile.GetInnermostTypeDefinition(textCursorLocation); if (curDef != null) { var resolvedDef = curDef.Resolve(typeResolveContext).GetDefinition(); typeResolveContext = typeResolveContext.WithCurrentTypeDefinition(resolvedDef); var curMember = resolvedDef.Members.FirstOrDefault(m => m.Region.Begin <= textCursorLocation && textCursorLocation < m.BodyRegion.End); if (curMember != null) { typeResolveContext = typeResolveContext.WithCurrentMember(curMember); } } #endregion // The purpose of the rest of these steps is a little fuzzy in my mind... // I'm still trying to understand them fully and if/why they're all needed. // It seems there is some redundancy here... var completionContext = new DefaultCompletionContextProvider(doc, fileModel.UnresolvedFile); #region Add Preprocessor Symbols?? completionContext.AddSymbol("TEST"); foreach (var sym in fileModel.SyntaxTree.ConditionalSymbols) { completionContext.AddSymbol(sym); } #endregion var completionDataFactory = new TestCompletionDataFactory(new CSharpResolver(typeResolveContext)); var completionEngine = new CSharpCompletionEngine(doc, completionContext, completionDataFactory, projectModel.ProjectContent, typeResolveContext); completionEngine.EolMarker = Environment.NewLine; completionEngine.FormattingPolicy = FormattingOptionsFactory.CreateMono(); projectModel.CompletionEngine = completionEngine; #region Debugging Aid // Resolve content around text cursor int numberOfCharactersAroundCursorToResolve = 20; int firstCharOffset = textCursorOffset - numberOfCharactersAroundCursorToResolve / 2; if (firstCharOffset < 0) { firstCharOffset = 0; } if (doc.TextLength < firstCharOffset + numberOfCharactersAroundCursorToResolve) { numberOfCharactersAroundCursorToResolve = doc.TextLength - firstCharOffset; } string surroundingText = doc.GetText(firstCharOffset, numberOfCharactersAroundCursorToResolve); Debug.WriteLine("Text around cursor: [{0}]", surroundingText); #endregion // Finally, generate completion data! var completionOptions = completionEngine.GetCompletionData(textCursorOffset, projectAnalysisRequest.CodeCompletionParameters.CtrlSpace).ToArray(); projectAnalysisResult.CompletionOptions = completionEngine.GetCompletionData(textCursorOffset, projectAnalysisRequest.CodeCompletionParameters.CtrlSpace).ToArray(); projectAnalysisResult.AutoCompleteEmptyMatch = completionEngine.AutoCompleteEmptyMatch; projectAnalysisResult.AutoSelect = completionEngine.AutoSelect; projectAnalysisResult.DefaultCompletionString = completionEngine.DefaultCompletionString; int startPos, wordLength; if (completionEngine.TryGetCompletionWord(textCursorOffset, out startPos, out wordLength)) { Debug.WriteLine("TryGetCompletionWord :: startpos:{0} wordlength:{1}", startPos, wordLength); projectAnalysisResult.CompletionWord = doc.GetText(startPos, wordLength); } projectAnalysisResult.TimeElapsed = sw.Elapsed; return(projectAnalysisResult); }
public override async Task <CommandResult> ExecuteAsync(ProjectOrSolution projectOrSolution, CancellationToken cancellationToken = default) { AssemblyResolver.Register(); var codeAnalyzerOptions = new CodeAnalyzerOptions( ignoreAnalyzerReferences: Options.IgnoreAnalyzerReferences, ignoreCompilerDiagnostics: Options.IgnoreCompilerDiagnostics, reportNotConfigurable: Options.ReportNotConfigurable, reportSuppressedDiagnostics: Options.ReportSuppressedDiagnostics, logAnalyzerExecutionTime: Options.ExecutionTime, severityLevel: SeverityLevel, supportedDiagnosticIds: Options.SupportedDiagnostics, ignoredDiagnosticIds: Options.IgnoredDiagnostics, projectNames: Options.Projects, ignoredProjectNames: Options.IgnoredProjects, language: Language); IEnumerable <AnalyzerAssembly> analyzerAssemblies = Options.AnalyzerAssemblies .SelectMany(path => AnalyzerAssemblyLoader.LoadFrom(path, loadFixers: false).Select(info => info.AnalyzerAssembly)); CultureInfo culture = (Options.Culture != null) ? CultureInfo.GetCultureInfo(Options.Culture) : null; var codeAnalyzer = new CodeAnalyzer( analyzerAssemblies: analyzerAssemblies, formatProvider: culture, options: codeAnalyzerOptions); if (projectOrSolution.IsProject) { Project project = projectOrSolution.AsProject(); WriteLine($"Analyze '{project.Name}'", ConsoleColor.Cyan, Verbosity.Minimal); Stopwatch stopwatch = Stopwatch.StartNew(); ProjectAnalysisResult result = await codeAnalyzer.AnalyzeProjectAsync(project, cancellationToken); stopwatch.Stop(); WriteLine($"Done analyzing project '{project.FilePath}' in {stopwatch.Elapsed:mm\\:ss\\.ff}", Verbosity.Minimal); if (Options.Output != null && result.Diagnostics.Any()) { DiagnosticXmlSerializer.Serialize(result, project, Options.Output, culture); } } else { Solution solution = projectOrSolution.AsSolution(); ImmutableArray <ProjectAnalysisResult> results = await codeAnalyzer.AnalyzeSolutionAsync(solution, cancellationToken); if (Options.Output != null && results.Any(f => f.Diagnostics.Any())) { DiagnosticXmlSerializer.Serialize(results, solution, Options.Output, culture); } } return(CommandResult.Success); }