public static ReachabilityAnalysis Create(Statement statement, AlAstResolver resolver = null, RecursiveDetectorVisitor recursiveDetectorVisitor = null, CancellationToken cancellationToken = default(CancellationToken)) { var cfgBuilder = new ControlFlowGraphBuilder(); var cfg = cfgBuilder.BuildControlFlowGraph(statement, resolver, cancellationToken); return(Create(cfg, recursiveDetectorVisitor, cancellationToken)); }
public Task <IContextAction[]> GetAvailableActionsAsync(EditorRefactoringContext context, CancellationToken cancellationToken) { ITextEditor editor = context.Editor; // grab SelectionStart/SelectionLength while we're still on the main thread int selectionStart = editor.SelectionStart; int selectionLength = editor.SelectionLength; return(Task.Run( async delegate { try { if (!CreateCodeActionProvider()) { return new IContextAction[0]; } AlAstResolver resolver = await context.GetAstResolverAsync().ConfigureAwait(false); var refactoringContext = new SDRefactoringContext(context.TextSource, resolver, context.CaretLocation, selectionStart, selectionLength, cancellationToken); return codeActionProvider.GetActions(refactoringContext).Select(Wrap).ToArray(); } catch (OperationCanceledException) { throw; // don't catch cancellations } catch (Exception ex) { SD.Log.WarnFormatted("AlContextActionProviderWrapper crashed: {0}", ex); SD.AnalyticsMonitor.TrackException(ex); return new IContextAction[0]; } }, cancellationToken)); }
public DefiniteAssignmentAnalysis(Statement rootStatement, AlAstResolver resolver, CancellationToken cancellationToken) { if (rootStatement == null) { throw new ArgumentNullException("rootStatement"); } if (resolver == null) { throw new ArgumentNullException("resolver"); } this.resolver = resolver; visitor.analysis = this; DerivedControlFlowGraphBuilder cfgBuilder = new DerivedControlFlowGraphBuilder(); if (resolver.TypeResolveContext.Compilation.MainAssembly.UnresolvedAssembly is MinimalCorlib) { cfgBuilder.EvaluateOnlyPrimitiveConstants = true; } allNodes.AddRange(cfgBuilder.BuildControlFlowGraph(rootStatement, resolver, cancellationToken).Cast <DefiniteAssignmentNode>()); for (int i = 0; i < allNodes.Count; i++) { DefiniteAssignmentNode node = allNodes[i]; node.Index = i; // assign numbers to the nodes if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements) { // Anonymous methods have separate control flow graphs, but we also need to analyze those. // Iterate backwards so that anonymous methods are inserted in the correct order for (AstNode child = node.NextStatement.LastChild; child != null; child = child.PrevSibling) { InsertAnonymousMethods(i + 1, child, cfgBuilder, cancellationToken); } } // Now register the node in the dictionaries: if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements) { beginNodeDict.Add(node.NextStatement, node); } if (node.Type == ControlFlowNodeType.BetweenStatements || node.Type == ControlFlowNodeType.EndNode) { endNodeDict.Add(node.PreviousStatement, node); } if (node.Type == ControlFlowNodeType.LoopCondition) { conditionNodeDict.Add(node.NextStatement, node); } } // Verify that we created nodes for all statements: Debug.Assert(!rootStatement.DescendantsAndSelf.OfType <Statement>().Except(allNodes.Select(n => n.NextStatement)).Any()); // Verify that we put all nodes into the dictionaries: Debug.Assert(rootStatement.DescendantsAndSelf.OfType <Statement>().All(stmt => beginNodeDict.ContainsKey(stmt))); Debug.Assert(rootStatement.DescendantsAndSelf.OfType <Statement>().All(stmt => endNodeDict.ContainsKey(stmt))); this.analyzedRangeStart = 0; this.analyzedRangeEnd = allNodes.Count - 1; }
public static bool TypeChangeResolvesCorrectly(BaseRefactoringContext ctx, ParameterDeclaration parameter, AstNode rootNode, IType type) { var resolver = ctx.GetResolverStateBefore(rootNode); resolver = resolver.AddVariable(new DefaultParameter(type, parameter.Name)); var astResolver = new AlAstResolver(resolver, rootNode, ctx.UnresolvedFile); var validator = new TypeChangeValidationNavigator(); astResolver.ApplyNavigator(validator, ctx.CancellationToken); return(!validator.FoundErrors); }
public IList <ControlFlowNode> BuildControlFlowGraph(Statement statement, AlAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken)) { if (statement == null) { throw new ArgumentNullException("statement"); } if (resolver == null) { throw new ArgumentNullException("resolver"); } return(BuildControlFlowGraph(statement, resolver.Resolve, resolver.TypeResolveContext, cancellationToken)); }
public SDRefactoringContext(ITextSource textSource, AlAstResolver resolver, TextLocation location, int selectionStart, int selectionLength, CancellationToken cancellationToken) : base(resolver, cancellationToken) { this.resolver = resolver; this.textSource = textSource; this.document = textSource as IDocument; this.selectionStart = selectionStart; this.selectionLength = selectionLength; this.location = location; this.editorOptions = SD.EditorControlService.GlobalOptions.ToEditorOptions(); InitializeServices(); }
public SDRefactoringContext(ITextEditor editor, AlAstResolver resolver, TextLocation location, CancellationToken cancellationToken = default(CancellationToken)) : base(resolver, cancellationToken) { this.resolver = resolver; this.editor = editor; this.textSource = editor.Document; this.document = editor.Document; this.selectionStart = editor.SelectionStart; this.selectionLength = editor.SelectionLength; this.location = location; this.editorOptions = editor.ToEditorOptions(); InitializeServices(); }
void VisitVisibleNodes(AstNode node, IResolveVisitorNavigator currentNavigator, AlAstResolver resolver, int start, int end) { if (!AlAstResolver.IsUnresolvableNode(node)) { currentNavigator.Resolved(node, resolver.Resolve(node)); } for (var child = node.FirstChild; child != null; child = child.NextSibling) { if (child.StartLocation.Line <= end && child.EndLocation.Line >= start) { VisitVisibleNodes(child, currentNavigator, resolver, start, end); } } }
public AlAstResolver GetResolver(ICompilation compilation) { // Cache the resolver within the compilation. // (caching in the parse information could prevent the compilation from being garbage-collected) // Also, don't cache AlAstResolvers for every file - doing so would require too much memory, // and we usually only need to access the same file several times. // So we use a static key to get the resolver, and verify that it belongs to this parse information. var resolver = compilation.CacheManager.GetShared(ResolverCacheKey) as AlAstResolver; if (resolver == null || resolver.RootNode != syntaxTree || resolver.UnresolvedFile != UnresolvedFile) { resolver = new AlAstResolver(compilation, syntaxTree, UnresolvedFile); compilation.CacheManager.SetShared(ResolverCacheKey, resolver); } return(resolver); }
public ICodeContext ResolveContext(ParseInformation parseInfo, TextLocation location, ICompilation compilation, CancellationToken cancellationToken) { var csParseInfo = parseInfo as AlFullParseInformation; if (csParseInfo == null) throw new ArgumentException("Parse info does not have SyntaxTree"); AlUnresolvedFile unresolvedFile = csParseInfo.UnresolvedFile; var projectContents = compilation.Assemblies.Select(asm => asm.UnresolvedAssembly).OfType<IProjectContent>().ToList(); if (projectContents.All(pc => pc.GetFile(unresolvedFile.FileName) != unresolvedFile)) unresolvedFile = null; var syntaxTree = csParseInfo.SyntaxTree; var node = syntaxTree.GetNodeAt(location); if (node == null) return null; // null result is allowed; the parser service will substitute a dummy context var resolver = new AlAstResolver(compilation, syntaxTree, unresolvedFile); return resolver.GetResolverStateBefore(node); }
public static SDRefactoringContext Create(FileName fileName, ITextSource textSource, TextLocation location = default(TextLocation), CancellationToken cancellationToken = default(CancellationToken)) { var parseInfo = SD.ParserService.Parse(fileName, textSource, cancellationToken: cancellationToken) as AlFullParseInformation; var compilation = SD.ParserService.GetCompilationForFile(fileName); AlAstResolver resolver; if (parseInfo != null) { resolver = parseInfo.GetResolver(compilation); } else { // create dummy refactoring context resolver = new AlAstResolver(compilation, new SyntaxTree()); } var context = new SDRefactoringContext(textSource, resolver, location, 0, 0, cancellationToken); return(context); }
public static SDRefactoringContext Create(ITextEditor editor, CancellationToken cancellationToken) { var parseInfo = SD.ParserService.Parse(editor.FileName, editor.Document, cancellationToken: cancellationToken) as AlFullParseInformation; var compilation = SD.ParserService.GetCompilationForFile(editor.FileName); AlAstResolver resolver; if (parseInfo != null) { resolver = parseInfo.GetResolver(compilation); } else { // create dummy refactoring context resolver = new AlAstResolver(compilation, new SyntaxTree()); } var context = new SDRefactoringContext(editor, resolver, editor.Caret.Location, cancellationToken); return(context); }
public ResolveResult ResolveSnippet(ParseInformation parseInfo, TextLocation location, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken) { var csParseInfo = parseInfo as AlFullParseInformation; if (csParseInfo == null) throw new ArgumentException("Parse info does not have SyntaxTree"); AlAstResolver contextResolver = new AlAstResolver(compilation, csParseInfo.SyntaxTree, csParseInfo.UnresolvedFile); var node = csParseInfo.SyntaxTree.GetNodeAt(location); AlResolver context; if (node != null) context = contextResolver.GetResolverStateAfter(node, cancellationToken); else context = new AlResolver(compilation); AlParser parser = new AlParser(); var expr = parser.ParseExpression(codeSnippet); if (parser.HasErrors) return new ErrorResolveResult(SpecialType.UnknownType, PrintErrorsAsString(parser.Errors), TextLocation.Empty); AlAstResolver snippetResolver = new AlAstResolver(context, expr); return snippetResolver.Resolve(expr, cancellationToken); }
void FindCurrentReferences(int start, int end) { ICompilation compilation = SD.ParserService.GetCompilationForFile(editor.FileName); AlFullParseInformation parseInfo = SD.ParserService.GetCachedParseInformation(editor.FileName) as AlFullParseInformation; if (currentSymbolReference == null || parseInfo == null) { return; } IResolveVisitorNavigator currentNavigator = InitNavigator(compilation); AlAstResolver resolver = parseInfo.GetResolver(compilation); if (currentNavigator == null || resolver == null) { return; } VisitVisibleNodes(parseInfo.SyntaxTree, currentNavigator, resolver, start, end); }
public ExpressionResolveResult(ResolveResult item1, AlResolver item2, AlAstResolver item3) { this.Result = item1; this.Resolver = item2; this.AstResolver = item3; }
void RenameReferencesInFile(SymbolRenameArgs args, IList <IFindReferenceSearchScope> searchScopeList, FileName fileName, Action <PatchedFile> callback, Action <Error> errorCallback, bool isNameValid, CancellationToken cancellationToken) { ITextSource textSource = args.ParseableFileContentFinder.Create(fileName); if (textSource == null) { return; } if (searchScopeList != null) { if (!searchScopeList.DistinctBy(scope => scope.SearchTerm ?? String.Empty).Any( scope => (scope.SearchTerm == null) || (textSource.IndexOf(scope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) >= 0))) { return; } } var parseInfo = SD.ParserService.Parse(fileName, textSource) as AlFullParseInformation; if (parseInfo == null) { return; } ReadOnlyDocument document = null; IHighlighter highlighter = null; List <RenameResultMatch> results = new List <RenameResultMatch>(); // Grab the unresolved file matching the compilation version // (this may differ from the version created by re-parsing the project) AlUnresolvedFile unresolvedFile = null; IProjectContent pc = compilation.MainAssembly.UnresolvedAssembly as IProjectContent; if (pc != null) { unresolvedFile = pc.GetFile(fileName) as AlUnresolvedFile; } AlAstResolver resolver = new AlAstResolver(compilation, parseInfo.SyntaxTree, unresolvedFile); fr.RenameReferencesInFile( searchScopeList, args.NewName, resolver, delegate(RenameCallbackArguments callbackArgs) { var node = callbackArgs.NodeToReplace; string newCode = callbackArgs.NewNode.ToString(); if (document == null) { document = new ReadOnlyDocument(textSource, fileName); if (args.ProvideHighlightedLine) { highlighter = SD.EditorControlService.CreateHighlighter(document); highlighter.BeginHighlighting(); } } var startLocation = node.StartLocation; var endLocation = node.EndLocation; int offset = document.GetOffset(startLocation); int length = document.GetOffset(endLocation) - offset; if (args.ProvideHighlightedLine) { var builder = SearchResultsPad.CreateInlineBuilder(node.StartLocation, node.EndLocation, document, highlighter); var defaultTextColor = highlighter != null ? highlighter.DefaultTextColor : null; results.Add(new RenameResultMatch(fileName, startLocation, endLocation, offset, length, newCode, builder, defaultTextColor)); } else { results.Add(new RenameResultMatch(fileName, startLocation, endLocation, offset, length, newCode)); } }, errorCallback, cancellationToken); if (highlighter != null) { highlighter.Dispose(); } if (results.Count > 0) { if (!isNameValid) { errorCallback(new Error(ErrorType.Error, string.Format("The name '{0}' is not valid in the current context!", args.NewName), new DomRegion(fileName, results[0].StartLocation))); return; } IDocument changedDocument = new TextDocument(document); var oldVersion = changedDocument.Version; List <SearchResultMatch> fixedResults = new List <SearchResultMatch>(); int lastStartOffset = changedDocument.TextLength + 1; foreach (var result in results.OrderByDescending(m => m.StartOffset)) { if (result.EndOffset <= lastStartOffset) { changedDocument.Replace(result.StartOffset, result.Length, result.NewCode); fixedResults.Add(result); lastStartOffset = result.StartOffset; } } callback(new PatchedFile(fileName, fixedResults, oldVersion, changedDocument.Version)); } }