/// <summary> /// Exports the specified component to a temporary file, loads, and then parses the exported file. /// </summary> /// <param name="component"></param> public IDictionary<Tuple<string, DeclarationType>, Attributes> Parse(VBComponent component) { var path = _exporter.Export(component); if (!File.Exists(path)) { // a document component without any code wouldn't be exported (file would be empty anyway). return new Dictionary<Tuple<string, DeclarationType>, Attributes>(); } var code = File.ReadAllText(path); File.Delete(path); var type = component.Type == vbext_ComponentType.vbext_ct_StdModule ? DeclarationType.Module : DeclarationType.Class; var listener = new AttributeListener(Tuple.Create(component.Name, type)); var stream = new AntlrInputStream(code); var lexer = new VBALexer(stream); var tokens = new CommonTokenStream(lexer); var parser = new VBAParser(tokens); // parse tree isn't usable for declarations because // line numbers are offset due to module header and attributes // (these don't show up in the VBE, that's why we're parsing an exported file) var tree = parser.startRule(); ParseTreeWalker.Default.Walk(listener, tree); return listener.Attributes; }
private static void ExportUserFormModule(VBComponent component, string path) { // VBIDE API inserts an extra newline when exporting a UserForm module. // this issue causes forms to always be treated as "modified" in source control, which causes conflicts. // we need to remove the extra newline before the file gets written to its output location. var visibleCode = component.CodeModule.Lines().Split(new []{Environment.NewLine}, StringSplitOptions.None); var legitEmptyLineCount = visibleCode.TakeWhile(string.IsNullOrWhiteSpace).Count(); var tempFile = component.ExportToTempFile(); var contents = File.ReadAllLines(tempFile); var nonAttributeLines = contents.TakeWhile(line => !line.StartsWith("Attribute")).Count(); var attributeLines = contents.Skip(nonAttributeLines).TakeWhile(line => line.StartsWith("Attribute")).Count(); var declarationsStartLine = nonAttributeLines + attributeLines + 1; var emptyLineCount = contents.Skip(declarationsStartLine - 1) .TakeWhile(string.IsNullOrWhiteSpace) .Count(); var code = contents; if (emptyLineCount > legitEmptyLineCount) { code = contents.Take(declarationsStartLine).Union( contents.Skip(declarationsStartLine + emptyLineCount - legitEmptyLineCount)) .ToArray(); } File.WriteAllLines(path, code); }
private static string GetNextTestMethodName(VBComponent component) { var names = component.TestMethods().Select(test => test.QualifiedMemberName.MemberName); var index = names.Count(n => n.StartsWith(TestMethodBaseName)) + 1; return string.Concat(TestMethodBaseName, index); }
private void OnDispatch(EventHandler<DispatcherEventArgs<VBComponent>> dispatched, VBComponent component) { var handler = dispatched; if (handler != null) { handler.Invoke(this, new DispatcherEventArgs<VBComponent>(component)); } }
public void ItemRenamed(VBComponent VBComponent, string OldName) { var handler = ComponentRenamed; if (handler != null) { handler.Invoke(this, new DispatcherRenamedEventArgs<VBComponent>(VBComponent, OldName)); } }
public ComponentParseTask(VBComponent vbComponent, VBAPreprocessor preprocessor, IAttributeParser attributeParser, TokenStreamRewriter rewriter = null) { _attributeParser = attributeParser; _preprocessor = preprocessor; _component = vbComponent; _rewriter = rewriter; _qualifiedName = new QualifiedModuleName(vbComponent); }
public Mock<VBE> BuildFromSingleModule(string content, vbext_ComponentType type, out VBComponent component) { var builder = ProjectBuilder("TestProject1", vbext_ProjectProtection.vbext_pp_none); builder.AddComponent("TestModule1", type, content); var project = builder.Build(); component = project.Object.VBComponents.Item(0); return AddProject(project).Build(); }
public void ItemRenamed(VBComponent VBComponent, string OldName) { var handler = ComponentRenamed; if (handler != null) { handler.Invoke(this, new DispatcherRenamedEventArgs <VBComponent>(VBComponent, OldName)); } }
private static void ExportDocumentModule(VBComponent component, string path) { var lineCount = component.CodeModule.CountOfLines; if (lineCount > 0) { var text = component.CodeModule.Lines[1, lineCount]; File.WriteAllText(path, text); } }
private void OnParseProgress(VBComponent component) { var handler = ParseProgress; if (handler != null) { handler(this, new ParseProgressEventArgs(component)); } }
public ComponentParseTask(VBComponent vbComponent, IVBAPreprocessor preprocessor, IAttributeParser attributeParser, TokenStreamRewriter rewriter = null) { _attributeParser = attributeParser; _preprocessor = preprocessor; _component = vbComponent; _rewriter = rewriter; _qualifiedName = new QualifiedModuleName(vbComponent); _parser = new VBAModuleParser(); }
private void OnResolveProgress(VBComponent component) { var handler = ResolutionProgress; if (handler != null) { handler(this, new ResolutionProgressEventArgs(component)); } }
/// <summary> /// Ensures parser state accounts for built-in declarations. /// </summary> /// <summary> /// Requests reparse for specified component. /// Omit parameter to request a full reparse. /// </summary> /// <param name="requestor">The object requesting a reparse.</param> /// <param name="component">The component to reparse.</param> public void OnParseRequested(object requestor, VBComponent component = null) { var handler = ParseRequest; if (handler != null) { var args = new ParseRequestEventArgs(component); handler.Invoke(requestor, args); } }
private void LogParseException(VBComponent component, SyntaxErrorException exception) { var offendingProject = component.Collection.Parent.Name; var offendingComponent = component.Name; var offendingLine = component.CodeModule.get_Lines(exception.LineNumber, 1); var message = string.Format("Parser encountered a syntax error in {0}.{1}, line {2}. Content: '{3}'", offendingProject, offendingComponent, exception.LineNumber, offendingLine); _logger.ErrorException(message, exception); }
private void OnModuleStateChanged(VBComponent component, ParserState state) { var handler = ModuleStateChanged; if (handler != null) { var args = new ParseProgressEventArgs(component, state); handler.Invoke(this, args); } }
public IEnumerable <CommentNode> GetModuleComments(VBComponent component) { ModuleState state; if (_moduleStates.TryGetValue(new QualifiedModuleName(component), out state)) { return(state.Comments); } return(new List <CommentNode>()); }
public IEnumerable <CommentNode> GetModuleComments(VBComponent component) { IList <CommentNode> result; if (_comments.TryGetValue(new QualifiedModuleName(component), out result)) { return(result); } return(new List <CommentNode>()); }
public IEnumerable <IAnnotation> GetModuleAnnotations(VBComponent component) { ModuleState result; if (_moduleStates.TryGetValue(new QualifiedModuleName(component), out result)) { return(result.Annotations); } return(new List <IAnnotation>()); }
/// <summary> /// Runs all methods with specified attribute. /// </summary> /// <typeparam name="TAttribute"></typeparam> /// <param name="component"></param> /// <remarks> /// Order of execution cannot be garanteed. /// </remarks> public static void RunMethodsWithAttribute <TAttribute>(this VBComponent component) where TAttribute : MemberAttributeBase, new() { var hostApp = component.VBE.HostApplication(); var methods = component.GetMembers(vbext_ProcKind.vbext_pk_Proc) .Where(member => member.HasAttribute <TAttribute>()); foreach (var method in methods) { hostApp.Run(method.QualifiedMemberName); } }
public static IEnumerable <TestMethod> TestMethods(this VBComponent component) { IHostApplication hostApp = component.VBE.HostApplication(); if (component.Type == vbext_ComponentType.vbext_ct_StdModule && component.CodeModule.HasAttribute <TestModuleAttribute>()) { return(component.GetMembers().Where(member => IsTestMethod(member)) .Select(member => new TestMethod(component.Collection.Parent.Name, component.Name, member.Name, hostApp))); } return(new List <TestMethod>()); }
public static IEnumerable <TestMethod> TestMethods(this VBComponent component) { if (component.Type == vbext_ComponentType.vbext_ct_StdModule && component.CodeModule.HasAttribute <TestModuleAttribute>()) { return(component.GetMembers() .Where(IsTestMethod) .Select(member => new TestMethod(member.QualifiedMemberName, component.VBE))); } return(new List <TestMethod>()); }
public QualifiedModuleName(VBComponent component) { _component = component; _componentName = component == null ? string.Empty : component.Name; _projectName = component == null ? string.Empty : component.Collection.Parent.Name; _projectHashCode = component == null ? 0 : component.Collection.Parent.GetHashCode(); var module = _component.CodeModule; _contentHashCode = module.CountOfLines > 0 ? module.get_Lines(1, module.CountOfLines).GetHashCode() : 0; }
private Declaration FindModuleDeclaration(VBComponent component) { var projectId = component.Collection.Parent.HelpFile; var project = _state.AllUserDeclarations.SingleOrDefault(item => item.DeclarationType == DeclarationType.Project && item.ProjectId == projectId); var result = _state.AllUserDeclarations.SingleOrDefault(item => item.ProjectId == component.Collection.Parent.HelpFile && item.QualifiedName.QualifiedModuleName.ComponentName == component.Name && (item.DeclarationType == DeclarationType.Class || item.DeclarationType == DeclarationType.Module)); var declaration = new Declaration(new QualifiedMemberName(new QualifiedModuleName(component), component.Name), project, project.Scope, component.Name, false, false, Accessibility.Global, DeclarationType.Module, false); return result ?? declaration; // module isn't in parser state - give it a dummy declaration, just so the ViewModel has something to chew on }
public VBComponentParseResult(VBComponent component, IParseTree parseTree, IEnumerable<CommentNode> comments, ITokenStream tokenStream) { _component = component; _qualifiedName = new QualifiedModuleName(component); _parseTree = parseTree; _comments = comments; _tokenStream = tokenStream; var listener = new DeclarationSymbolsListener(_qualifiedName, Accessibility.Implicit, _component.Type); var walker = new ParseTreeWalker(); walker.Walk(listener, _parseTree); _declarations.AddRange(listener.Declarations.Items); }
private void OnParserError(SyntaxErrorException exception, VBComponent component) { if (LogManager.IsLoggingEnabled()) { LogParseException(exception, component); } var handler = ParserError; if (handler != null) { handler(this, new ParseErrorEventArgs(exception, component)); } }
private Task ParseAsync(VBComponent component, CancellationTokenSource token, TokenStreamRewriter rewriter = null) { State.ClearStateCache(component); var task = new Task(() => ParseAsyncInternal(component, token.Token, rewriter)); _currentTasks.TryAdd(component, Tuple.Create(task, token)); Tuple <Task, CancellationTokenSource> removedTask; task.ContinueWith(t => _currentTasks.TryRemove(component, out removedTask), token.Token); // default also executes on cancel // See http://stackoverflow.com/questions/6800705/why-is-taskscheduler-current-the-default-taskscheduler task.Start(TaskScheduler.Default); return(task); }
public QualifiedModuleName(VBComponent component) { _project = null; // field is only assigned when the instance refers to a VBProject. _component = component; _componentName = component == null ? string.Empty : component.Name; _projectName = component == null ? string.Empty : component.Collection.Parent.Name; _projectHashCode = component == null ? 0 : component.Collection.Parent.GetHashCode(); var module = _component.CodeModule; _contentHashCode = module.CountOfLines > 0 ? module.get_Lines(1, module.CountOfLines).GetHashCode() : 0; }
public VBComponentParseResult(VBComponent component, IParseTree parseTree, IEnumerable <CommentNode> comments, ITokenStream tokenStream) { _component = component; _qualifiedName = new QualifiedModuleName(component); _parseTree = parseTree; _comments = comments; _tokenStream = tokenStream; var listener = new DeclarationSymbolsListener(_qualifiedName, Accessibility.Implicit, _component.Type); var walker = new ParseTreeWalker(); walker.Walk(listener, _parseTree); _declarations.AddRange(listener.Declarations.Items); }
private Declaration FindModuleDeclaration(VBComponent component) { var projectId = component.Collection.Parent.HelpFile; var project = _state.AllUserDeclarations.SingleOrDefault(item => item.DeclarationType == DeclarationType.Project && item.ProjectId == projectId); var result = _state.AllUserDeclarations.SingleOrDefault(item => item.ProjectId == component.Collection.Parent.HelpFile && item.QualifiedName.QualifiedModuleName.ComponentName == component.Name && (item.DeclarationType == DeclarationType.ClassModule || item.DeclarationType == DeclarationType.ProceduralModule)); var declaration = new Declaration(new QualifiedMemberName(new QualifiedModuleName(component), component.Name), project, project.Scope, component.Name, false, false, Accessibility.Global, DeclarationType.ProceduralModule, false); return(result ?? declaration); // module isn't in parser state - give it a dummy declaration, just so the ViewModel has something to chew on }
/// <summary> /// Scans form designer to create a public, self-assigned field for each control on a form. /// </summary> /// <remarks> /// These declarations are meant to be used to identify control event procedures. /// </remarks> private void DeclareControlsAsMembers(VBComponent form) { var designer = form.Designer; if (designer == null) { return; } // using dynamic typing here, because not only MSForms could have a Controls collection (e.g. MS-Access forms are 'document' modules). foreach (var control in ((dynamic)designer).Controls) { var declaration = new Declaration(_qualifiedName.QualifyMemberName(control.Name), _parentDeclaration, _currentScopeDeclaration, "Control", true, true, Accessibility.Public, DeclarationType.Control, null, Selection.Home); OnNewDeclaration(declaration); } }
public override void Execute(object parameter) { var declarations = _state.AllDeclarations; var qualifiedSelection = Vbe.ActiveCodePane.GetQualifiedSelection(); var extractMethodValidation = new ExtractMethodSelectionValidation(declarations); var canExecute = extractMethodValidation.withinSingleProcedure(qualifiedSelection.Value); if (!canExecute) { return; } ICodeModuleWrapper codeModuleWrapper = new CodeModuleWrapper(Vbe.ActiveCodePane.CodeModule); VBComponent vbComponent = Vbe.SelectedVBComponent; Func <QualifiedSelection?, string, IExtractMethodModel> createMethodModel = (qs, code) => { if (qs == null) { return(null); } //TODO: Pull these even further back; // and implement with IProvider<IExtractMethodRule> var rules = new List <IExtractMethodRule>() { new ExtractMethodRuleInSelection(), new ExtractMethodRuleIsAssignedInSelection(), new ExtractMethodRuleUsedAfter(), new ExtractMethodRuleUsedBefore() }; var paramClassify = new ExtractMethodParameterClassification(rules); var extractedMethod = new ExtractedMethod(); var extractedMethodModel = new ExtractMethodModel(extractedMethod, paramClassify); extractedMethodModel.extract(declarations, qs.Value, code); return(extractedMethodModel); }; var extraction = new ExtractMethodExtraction(); Action <Object> parseRequest = (obj) => _state.OnParseRequested(obj, vbComponent); var refactoring = new ExtractMethodRefactoring(codeModuleWrapper, parseRequest, createMethodModel, extraction); refactoring.InvalidSelection += HandleInvalidSelection; refactoring.Refactor(); }
/// <summary> /// Safely removes the specified VbComponent from the collection. /// </summary> /// <remarks> /// UserForms, Class modules, and Standard modules are completely removed from the project. /// Since Document type components can't be removed through the VBE, all code in its CodeModule are deleted instead. /// </remarks> public static void RemoveSafely(this VBComponents components, VBComponent component) { switch (component.Type) { case vbext_ComponentType.vbext_ct_ClassModule: case vbext_ComponentType.vbext_ct_StdModule: case vbext_ComponentType.vbext_ct_MSForm: components.Remove(component); break; case vbext_ComponentType.vbext_ct_ActiveXDesigner: case vbext_ComponentType.vbext_ct_Document: component.CodeModule.Clear(); break; default: break; } }
private void bruteforce() { lbl_status.Text = "In progress..."; lbl_status.ForeColor = Color.Orange; try { InitRegKey(); var excel = new Application(); var wbs = excel.Workbooks; Workbook wb = wbs.Open(filename); Worksheet sheet = (Worksheet)wb.ActiveSheet; /*if (wb.HasVBProject) * {*/ VBProject project = wb.VBProject; VBComponent module = project.VBComponents.Add(vbext_ComponentType.vbext_ct_StdModule); module.CodeModule.AddFromString(script); wb.Application.Run("Unlocker"); excel.Visible = false; excel.UserControl = false; //} project.VBComponents.Remove(module); wb.Save(); wb.Close(); excel.Workbooks.Close(); excel.Quit(); } catch (Exception e) { lbl_status.Text = "Failed"; lbl_status.ForeColor = Color.Red; } lbl_status.Text = "Success!"; lbl_status.ForeColor = Color.Green; //vba scripts: //http://jsbi.blogspot.com/2008/09/how-to-easily-unprotectremove-password.html //https://exceloffthegrid.com/removing-cracking-excel-passwords-with-vba/ //details sur la methode de hash d'excel //https://stackoverflow.com/questions/19953979/cracking-sheet-password-with-vba/19958159 }
private Declaration CreateDeclaration(VBComponent component) { var projectDeclaration = _state.AllUserDeclarations.FirstOrDefault(item => item.DeclarationType == DeclarationType.Project && item.Project.VBComponents.Cast <VBComponent>().Contains(component)); if (component.Type == vbext_ComponentType.vbext_ct_StdModule) { return(new ProceduralModuleDeclaration( new QualifiedMemberName(new QualifiedModuleName(component), component.Name), projectDeclaration, component.Name, false, new List <IAnnotation>(), null)); } return(new ClassModuleDeclaration(new QualifiedMemberName(new QualifiedModuleName(component), component.Name), projectDeclaration, component.Name, false, new List <IAnnotation>(), null)); }
private void ResolveDeclarations(VBComponent component, IParseTree tree) { var qualifiedModuleName = new QualifiedModuleName(component); var obsoleteCallStatementListener = new ObsoleteCallStatementListener(); var obsoleteLetStatementListener = new ObsoleteLetStatementListener(); var emptyStringLiteralListener = new EmptyStringLiteralListener(); var argListWithOneByRefParamListener = new ArgListWithOneByRefParamListener(); try { ParseTreeWalker.Default.Walk(new CombinedParseTreeListener(new IParseTreeListener[] { obsoleteCallStatementListener, obsoleteLetStatementListener, emptyStringLiteralListener, argListWithOneByRefParamListener, }), tree); // TODO: these are actually (almost) inspection results.. we should handle them as such _state.ArgListsWithOneByRefParam = argListWithOneByRefParamListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); _state.EmptyStringLiterals = emptyStringLiteralListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); _state.ObsoleteLetContexts = obsoleteLetStatementListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); _state.ObsoleteCallContexts = obsoleteCallStatementListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); var project = component.Collection.Parent; var projectQualifiedName = new QualifiedModuleName(project); Declaration projectDeclaration; if (!_projectDeclarations.TryGetValue(projectQualifiedName.ProjectId, out projectDeclaration)) { projectDeclaration = CreateProjectDeclaration(projectQualifiedName, project); _projectDeclarations.Add(projectQualifiedName.ProjectId, projectDeclaration); _state.AddDeclaration(projectDeclaration); } var declarationsListener = new DeclarationSymbolsListener(qualifiedModuleName, Accessibility.Implicit, component.Type, _state.GetModuleComments(component), _state.GetModuleAnnotations(component), _state.GetModuleAttributes(component), _projectReferences, projectDeclaration); // TODO: should we unify the API? consider working like the other listeners instead of event-based declarationsListener.NewDeclaration += (sender, e) => _state.AddDeclaration(e.Declaration); declarationsListener.CreateModuleDeclarations(); // rewalk parse tree for second declaration level Debug.WriteLine("Walking parse tree for '{0}'... (acquiring declarations)", qualifiedModuleName.Name); ParseTreeWalker.Default.Walk(declarationsListener, tree); } catch (Exception exception) { Debug.Print("Exception thrown acquiring declarations for '{0}' (thread {2}): {1}", component.Name, exception, Thread.CurrentThread.ManagedThreadId); _state.SetModuleState(component, ParserState.ResolverError); } }
/// <summary> /// Scans form designer to create a public, self-assigned field for each control on a form. /// </summary> /// <remarks> /// These declarations are meant to be used to identify control event procedures. /// </remarks> private void DeclareControlsAsMembers(VBComponent form) { if (form.Type != vbext_ComponentType.vbext_ct_MSForm) { throw new InvalidOperationException(); } var designer = form.Designer; if (designer == null) { return; } foreach (var control in ((dynamic)designer).Controls) { _declarations.Add(new Declaration(_qualifiedName.QualifyMemberName(control.Name), _currentScope, "Control", true, true, Accessibility.Public, DeclarationType.Control, null, Selection.Home)); } }
/// <summary> /// Exports the component to the directoryPath. The file is name matches the component name and file extension is based on the component's type. /// </summary> /// <param name="component">The component to be exported to the file system.</param> /// <param name="directoryPath">Destination Path for the resulting source file.</param> public static void ExportAsSourceFile(this VBComponent component, string directoryPath) { string filePath = Path.Combine(directoryPath, component.Name + component.Type.FileExtension()); if (component.Type == vbext_ComponentType.vbext_ct_Document) { int lineCount = component.CodeModule.CountOfLines; if (lineCount > 0) { var text = component.CodeModule.get_Lines(1, lineCount); File.WriteAllText(filePath, text); } } else { component.Export(filePath); } }
public ParserState GetOrCreateModuleState(VBComponent component) { var key = new QualifiedModuleName(component); var state = _moduleStates.GetOrAdd(key, new ModuleState(ParserState.Pending)).State; if (state == ParserState.Pending) { return(state); // we are slated for a reparse already } if (!IsNewOrModified(key)) { return(state); } _moduleStates.AddOrUpdate(key, new ModuleState(ParserState.Pending), (c, s) => s.SetState(ParserState.Pending)); return(ParserState.Pending); }
public void HandleRemovedComponent(VBComponent component) { if (Provider == null || !Provider.HandleVbeSinkEvents) { return; } if (component.Collection.Parent.HelpFile != Provider.CurrentRepository.Id) { return; } var fileStatus = Provider.Status().SingleOrDefault(stat => stat.FilePath.Split('.')[0] == component.Name); if (fileStatus != null) { Provider.RemoveFile(fileStatus.FilePath, true); } }
public Task ParseAsync(VBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null) { _state.ClearStateCache(component); _state.SetModuleState(component, ParserState.Pending); // also clears module-exceptions var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_central.Token, token); //var taskFactory = new TaskFactory(new StaTaskScheduler()); var task = new Task(() => ParseAsyncInternal(component, linkedTokenSource.Token, rewriter)); _currentTasks.TryAdd(component, Tuple.Create(task, linkedTokenSource)); Tuple <Task, CancellationTokenSource> removedTask; task.ContinueWith(t => _currentTasks.TryRemove(component, out removedTask)); // default also executes on cancel task.Start(/*taskFactory.Scheduler*/); return(task); }
public QualifiedModuleName(VBComponent component) { _project = null; // field is only assigned when the instance refers to a VBProject. _component = component; _componentName = component == null ? string.Empty : component.Name; _project = component == null ? null : component.Collection.Parent; _projectName = _project == null ? string.Empty : _project.Name; _projectPath = string.Empty; _projectId = GetProjectId(_project); _contentHashCode = 0; if (component == null) { return; } var module = component.CodeModule; _contentHashCode = module.CountOfLines > 0 // ReSharper disable once UseIndexedProperty ? module.get_Lines(1, module.CountOfLines).GetHashCode() : 0; }
private VBComponentParseResult Parse(VBComponent component, out bool cached) { try { VBComponentParseResult cachedValue; var name = new QualifiedModuleName(component); // already a performance hit if (ParseResultCache.TryGetValue(name, out cachedValue)) { cached = true; return cachedValue; } var codeModule = component.CodeModule; var lines = codeModule.Lines(); ITokenStream stream; var parseTree = Parse(lines, out stream); var comments = ParseComments(name); var result = new VBComponentParseResult(component, parseTree, comments, stream); var existing = ParseResultCache.Keys.SingleOrDefault(k => k.Project == name.Project && k.ComponentName == name.ComponentName); VBComponentParseResult removed; ParseResultCache.TryRemove(existing, out removed); ParseResultCache.AddOrUpdate(name, module => result, (qName, module) => result); cached = false; return result; } catch (SyntaxErrorException exception) { OnParserError(exception, component); cached = false; return null; } catch (COMException) { cached = false; return null; } }
private void ResolveReferences(DeclarationFinder finder, VBComponent component, IParseTree tree) { var state = _state.GetModuleState(component); if (_state.Status == ParserState.ResolverError || (state != ParserState.Parsed)) { return; } Debug.WriteLine("Resolving '{0}'... (thread {1})", component.Name, Thread.CurrentThread.ManagedThreadId); var qualifiedName = new QualifiedModuleName(component); var resolver = new IdentifierReferenceResolver(qualifiedName, finder); var listener = new IdentifierReferenceListener(resolver); if (!string.IsNullOrWhiteSpace(tree.GetText().Trim())) { var walker = new ParseTreeWalker(); try { walker.Walk(listener, tree); state = ParserState.Ready; } catch (Exception exception) { Debug.Print("Exception thrown resolving '{0}' (thread {2}): {1}", component.Name, exception, Thread.CurrentThread.ManagedThreadId); state = ParserState.ResolverError; } } _state.SetModuleState(component, state); Debug.Print("'{0}' is {1}. Resolver took {2}ms to complete (thread {3})", component.Name, _state.GetModuleState(component), /*_resolverTimer[component].ElapsedMilliseconds*/0, Thread.CurrentThread.ManagedThreadId); }
private void LogVbComponent(VBComponent vbComponent) { Log(vbComponent.Name + " (" + vbComponent.Type.AsString() + ")"); }
private static string GetFileExtensionFor(VBComponent vbComp) { switch (vbComp.Type) { case vbext_ComponentType.vbext_ct_ClassModule: return ".cls"; case vbext_ComponentType.vbext_ct_Document: return ".wks"; case vbext_ComponentType.vbext_ct_MSForm: return ".frm"; case vbext_ComponentType.vbext_ct_StdModule: return ".bas"; default: return ".bas"; } }
public Task ParseAsync(VBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null) { _state.ClearDeclarations(component); _state.SetModuleState(component, ParserState.Pending); // also clears module-exceptions var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_central.Token, token); //var taskFactory = new TaskFactory(new StaTaskScheduler()); var task = new Task(() => ParseAsyncInternal(component, linkedTokenSource.Token, rewriter)); _currentTasks.TryAdd(component, Tuple.Create(task, linkedTokenSource)); Tuple<Task, CancellationTokenSource> removedTask; task.ContinueWith(t => _currentTasks.TryRemove(component, out removedTask)); // default also executes on cancel task.Start(/*taskFactory.Scheduler*/); return task; }
private string QualifyComponentName(VBComponent component) { return component.Collection.Parent.Name + "." + component.Name; }
private void LogParseException(SyntaxErrorException exception, VBComponent component) { var offendingProject = component.Collection.Parent.Name; var offendingComponent = component.Name; var offendingLine = component.CodeModule.get_Lines(exception.LineNumber, 1); var message = string.Format("Parser encountered a syntax error in {0}.{1}, line {2}. Content: '{3}'", offendingProject, offendingComponent, exception.LineNumber, offendingLine); _logger.ErrorException(message, exception); }
private void ResolveDeclarations(VBComponent component, IParseTree tree) { var qualifiedModuleName = new QualifiedModuleName(component); var obsoleteCallStatementListener = new ObsoleteCallStatementListener(); var obsoleteLetStatementListener = new ObsoleteLetStatementListener(); var emptyStringLiteralListener = new EmptyStringLiteralListener(); var argListWithOneByRefParamListener = new ArgListWithOneByRefParamListener(); try { ParseTreeWalker.Default.Walk(new CombinedParseTreeListener(new IParseTreeListener[]{ obsoleteCallStatementListener, obsoleteLetStatementListener, emptyStringLiteralListener, argListWithOneByRefParamListener, }), tree); // TODO: these are actually (almost) isnpection results.. we should handle them as such _state.ArgListsWithOneByRefParam = argListWithOneByRefParamListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); _state.EmptyStringLiterals = emptyStringLiteralListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); _state.ObsoleteLetContexts = obsoleteLetStatementListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); _state.ObsoleteCallContexts = obsoleteCallStatementListener.Contexts.Select(context => new QualifiedContext(qualifiedModuleName, context)); // cannot locate declarations in one pass *the way it's currently implemented*, // because the context in EnterSubStmt() doesn't *yet* have child nodes when the context enters. // so we need to EnterAmbiguousIdentifier() and evaluate the parent instead - this *might* work. var declarationsListener = new DeclarationSymbolsListener(qualifiedModuleName, Accessibility.Implicit, component.Type, _state.GetModuleComments(component), _state.GetModuleAnnotations(component),_state.GetModuleAttributes(component), _references); // TODO: should we unify the API? consider working like the other listeners instead of event-based declarationsListener.NewDeclaration += (sender, e) => _state.AddDeclaration(e.Declaration); declarationsListener.CreateModuleDeclarations(); // rewalk parse tree for second declaration level ParseTreeWalker.Default.Walk(declarationsListener, tree); } catch (Exception exception) { Debug.Print("Exception thrown resolving '{0}' (thread {2}): {1}", component.Name, exception, Thread.CurrentThread.ManagedThreadId); _state.SetModuleState(component, ParserState.ResolverError); } }
public void ExtractVBComponent(VBComponent comp, string path, string fName, bool overwrite) { // do we need to export component? if (comp.CodeModule.CountOfLines == 0) { return; } // define file name var extension = GetFileExtensionFor(comp); if (fName.Trim() == String.Empty) { fName = comp.Name + extension; } else if (fName.IndexOf("."[0]) == 0) { fName = fName + extension; } // define folder path if (path.EndsWith(@"\", StringComparison.CurrentCultureIgnoreCase)) { fName = path + fName; } else { fName = path + @"\" + fName; } // is it possible to write to path FileInfo file = new FileInfo(fName); if (file.Exists) { if (overwrite) { file.Delete(); } } comp.Export(fName); }
private void ParseAsyncInternal(VBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null) { var preprocessor = new VBAPreprocessor(double.Parse(_vbe.Version, CultureInfo.InvariantCulture)); var parser = new ComponentParseTask(component, preprocessor, _attributeParser, rewriter); parser.ParseFailure += (sender, e) => _state.SetModuleState(component, ParserState.Error, e.Cause as SyntaxErrorException); parser.ParseCompleted += (sender, e) => { // possibly lock _state _state.SetModuleAttributes(component, e.Attributes); _state.AddParseTree(component, e.ParseTree); _state.AddTokenStream(component, e.Tokens); _state.SetModuleComments(component, e.Comments); _state.SetModuleAnnotations(component, e.Annotations); // This really needs to go last _state.SetModuleState(component, ParserState.Parsed); }; _state.SetModuleState(component, ParserState.Parsing); parser.Start(token); }
public void Cancel(VBComponent component = null) { lock (_central) lock (_resolverTokenSource) { if (component == null) { _central.Cancel(false); _central.Dispose(); _central = new CancellationTokenSource(); _resolverTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_central.Token); } else { _resolverTokenSource.Cancel(false); _resolverTokenSource.Dispose(); _resolverTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_central.Token); Tuple<Task, CancellationTokenSource> result; if (_currentTasks.TryGetValue(component, out result)) { result.Item2.Cancel(false); result.Item2.Dispose(); } } } }
public string Export(VBComponent component) { return component.ExportAsSourceFile(ExportPath); }
private void ParseComponent(VBComponent component, TokenStreamRewriter rewriter = null) { ParseAsync(component, CancellationToken.None, rewriter).Wait(); }