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 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;
        }
Example #4
0
        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);
        }
Example #5
0
        //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);
        }
Example #7
0
        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);
        }
        private static FileOperationResponse Server_HandleStatefulFileOperationRequest(FileOperationRequest request)
        {
            FileOperationResponse response = new FileOperationResponse();

            ProjectModel projectModel = null;
            ProjectFileModel fileModel = null;

            try
            {
                projectModel = ServerProjectRepository.GetProject(request.UserId, request.ProjectId);
                if (projectModel == null)
                {
                    response.SetError("Specified project could not be located.");
                    return response;
                }

                fileModel = ServerProjectRepository.GetFile(request.UserId, request.ProjectId, request.FileId);
                if (fileModel == null)
                {
                    response.SetError("Specified file could not be located within the project.");
                    return response;
                }
            }
            catch (Exception ex)
            {
                response.SyncContent.SetError(ex);
            }


            // Set contextual identifiers on response
            response.UserId = request.UserId;
            response.ProjectId = request.ProjectId;
            response.FileId = request.FileId;

            // Now, handle each requested operation...

            if (request.SyncContent != null)
            {
                response.SyncContent = new FileSyncContentResponse();

                fileModel.Content = request.SyncContent.Content;
                response.SyncContent.Status = ResponseStatus.OK;
            }


            if (request.Parse != null)
            {
                response.Parse = new FileParseResponse();

                try
                {
                    response.Parse.Errors = NRefactoryUtils.ParseFile(fileModel);
                    response.Parse.Status = ResponseStatus.OK;
                }
                catch (Exception ex)
                {
                    response.Parse.SetError(ex);
                }
            }


            if (request.CompleteCode != null)
            {
                response.CompleteCode = new FileCodeCompletionResponse();

                try
                {
                    var analysisRequest = new ProjectAnalysisRequest()
                    {
                        ProjectModel = projectModel,
                        CodeCompletionParameters = new ProjectAnalysisCodeCompletionParameters()
                        {
                            FileId = request.FileId,
                            Line = request.CompleteCode.LineNumber,
                            Column = request.CompleteCode.ColumnNumber
                        }
                    };

                    var analysisResult = NRefactoryUtils.RunFullProjectAnalysis(analysisRequest);
                    
                    response.CompleteCode.CompletionOptions = analysisResult.CompletionOptions.Select(x => new FileCodeCompletionResult()
                    {
                        CompletionText = x.CompletionText,
                        DisplayText = x.DisplayText
                    }).ToArray();
                    response.CompleteCode.Status = ResponseStatus.OK;
                }
                catch (Exception ex)
                {
                    response.CompleteCode.SetError(ex);
                }
            }

            response.Status = ResponseStatus.OK;
            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;
        }
        private static FileOperationResponse Server_HandleStatefulFileOperationRequest(FileOperationRequest request)
        {
            FileOperationResponse response = new FileOperationResponse();

            ProjectModel     projectModel = null;
            ProjectFileModel fileModel    = null;

            try
            {
                projectModel = ServerProjectRepository.GetProject(request.UserId, request.ProjectId);
                if (projectModel == null)
                {
                    response.SetError("Specified project could not be located.");
                    return(response);
                }

                fileModel = ServerProjectRepository.GetFile(request.UserId, request.ProjectId, request.FileId);
                if (fileModel == null)
                {
                    response.SetError("Specified file could not be located within the project.");
                    return(response);
                }
            }
            catch (Exception ex)
            {
                response.SyncContent.SetError(ex);
            }


            // Set contextual identifiers on response
            response.UserId    = request.UserId;
            response.ProjectId = request.ProjectId;
            response.FileId    = request.FileId;

            // Now, handle each requested operation...

            if (request.SyncContent != null)
            {
                response.SyncContent = new FileSyncContentResponse();

                fileModel.Content           = request.SyncContent.Content;
                response.SyncContent.Status = ResponseStatus.OK;
            }


            if (request.Parse != null)
            {
                response.Parse = new FileParseResponse();

                try
                {
                    response.Parse.Errors = NRefactoryUtils.ParseFile(fileModel);
                    response.Parse.Status = ResponseStatus.OK;
                }
                catch (Exception ex)
                {
                    response.Parse.SetError(ex);
                }
            }


            if (request.CompleteCode != null)
            {
                response.CompleteCode = new FileCodeCompletionResponse();

                try
                {
                    var analysisRequest = new ProjectAnalysisRequest()
                    {
                        ProjectModel             = projectModel,
                        CodeCompletionParameters = new ProjectAnalysisCodeCompletionParameters()
                        {
                            FileId = request.FileId,
                            Line   = request.CompleteCode.LineNumber,
                            Column = request.CompleteCode.ColumnNumber
                        }
                    };

                    var analysisResult = NRefactoryUtils.RunFullProjectAnalysis(analysisRequest);

                    response.CompleteCode.CompletionOptions = analysisResult.CompletionOptions.Select(x => new FileCodeCompletionResult()
                    {
                        CompletionText = x.CompletionText,
                        DisplayText    = x.DisplayText
                    }).ToArray();
                    response.CompleteCode.Status = ResponseStatus.OK;
                }
                catch (Exception ex)
                {
                    response.CompleteCode.SetError(ex);
                }
            }

            response.Status = ResponseStatus.OK;
            return(response);
        }