diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs index 71743c984e..abcbfb0077 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs @@ -19,7 +19,7 @@ namespace CSharpBinding.Parser { public class TParser : IParser { - ///IParser Interface + ///IParser Interface string[] lexerTags; public string[] LexerTags { @@ -53,7 +53,7 @@ namespace CSharpBinding.Parser ICSharpCode.NRefactory.Parser.PreProcessingDirective directive = tracker.CurrentSpecials[i] as ICSharpCode.NRefactory.Parser.PreProcessingDirective; if (directive != null) { if (directive.Cmd == "#region") { - int deep = 1; + int deep = 1; for (int j = i + 1; j < tracker.CurrentSpecials.Count; ++j) { ICSharpCode.NRefactory.Parser.PreProcessingDirective nextDirective = tracker.CurrentSpecials[j] as ICSharpCode.NRefactory.Parser.PreProcessingDirective; if (nextDirective != null) { @@ -81,37 +81,31 @@ namespace CSharpBinding.Parser { Properties textEditorProperties = ((Properties)PropertyService.Get("ICSharpCode.TextEditor.Document.Document.DefaultDocumentAggregatorProperties", new Properties())); using (ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(fileName, Encoding.GetEncoding(textEditorProperties.Get("Encoding", 1252)))) { - p.Lexer.SpecialCommentTags = lexerTags; - p.Parse(); - - NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); - visitor.Visit(p.CompilationUnit, null); - visitor.Cu.FileName = fileName; - visitor.Cu.ErrorsDuringCompile = p.Errors.count > 0; - RetrieveRegions(visitor.Cu, p.Lexer.SpecialTracker); - AddCommentTags(visitor.Cu, p.Lexer.TagComments); - return visitor.Cu; + return Parse(p, fileName, projectContent); } } public ICompilationUnit Parse(IProjectContent projectContent, string fileName, string fileContent) - { + { using (ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(ICSharpCode.NRefactory.Parser.SupportedLanguages.CSharp, new StringReader(fileContent))) { - p.Lexer.SpecialCommentTags = lexerTags; - p.Parse(); - - NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); - visitor.Visit(p.CompilationUnit, null); - visitor.Cu.FileName = fileName; - visitor.Cu.ErrorsDuringCompile = p.Errors.count > 0; - visitor.Cu.Tag = p.CompilationUnit; - - RetrieveRegions(visitor.Cu, p.Lexer.SpecialTracker); - AddCommentTags(visitor.Cu, p.Lexer.TagComments); - return visitor.Cu; + return Parse(p, fileName, projectContent); } } + ICompilationUnit Parse(ICSharpCode.NRefactory.Parser.IParser p, string fileName, IProjectContent projectContent) + { + p.Lexer.SpecialCommentTags = lexerTags; + p.Parse(); + + NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); + visitor.Visit(p.CompilationUnit, null); + visitor.Cu.FileName = fileName; + visitor.Cu.ErrorsDuringCompile = p.Errors.count > 0; + RetrieveRegions(visitor.Cu, p.Lexer.SpecialTracker); + AddCommentTags(visitor.Cu, p.Lexer.TagComments); + return visitor.Cu; + } + void AddCommentTags(ICompilationUnit cu, ArrayList tagComments) { foreach (ICSharpCode.NRefactory.Parser.TagComment tagComment in tagComments) { @@ -124,7 +118,7 @@ namespace CSharpBinding.Parser public IResolver CreateResolver() { - return new ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver(ICSharpCode.NRefactory.Parser.SupportedLanguages.CSharp); + return new ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver(ICSharpCode.NRefactory.Parser.SupportedLanguages.CSharp); } ///////// IParser Interface END } diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs index 9449c761ee..e2c49d5f5c 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/Parser/Parser.cs @@ -94,36 +94,30 @@ namespace VBNetBinding.Parser { Properties textEditorProperties = ((Properties)PropertyService.Get("ICSharpCode.TextEditor.Document.Document.DefaultDocumentAggregatorProperties", new Properties())); using (ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(fileName, Encoding.GetEncoding(textEditorProperties.Get("Encoding", 1252)))) { - p.Lexer.SpecialCommentTags = lexerTags; - p.Parse(); - - NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); - visitor.Visit(p.CompilationUnit, null); - visitor.Cu.FileName = fileName; - visitor.Cu.ErrorsDuringCompile = p.Errors.count > 0; - RetrieveRegions(visitor.Cu, p.Lexer.SpecialTracker); - AddCommentTags(visitor.Cu, p.Lexer.TagComments); - return visitor.Cu; + return Parse(p, fileName, projectContent); } } public ICompilationUnit Parse(IProjectContent projectContent, string fileName, string fileContent) { using (ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(ICSharpCode.NRefactory.Parser.SupportedLanguages.VBNet, new StringReader(fileContent))) { - p.Lexer.SpecialCommentTags = lexerTags; - p.Parse(); - - NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); - visitor.Visit(p.CompilationUnit, null); - visitor.Cu.FileName = fileName; - visitor.Cu.ErrorsDuringCompile = p.Errors.count > 0; - visitor.Cu.Tag = p.CompilationUnit; - - RetrieveRegions(visitor.Cu, p.Lexer.SpecialTracker); - AddCommentTags(visitor.Cu, p.Lexer.TagComments); - return visitor.Cu; + return Parse(p, fileName, projectContent); } } + + ICompilationUnit Parse(ICSharpCode.NRefactory.Parser.IParser p, string fileName, IProjectContent projectContent) + { + p.Lexer.SpecialCommentTags = lexerTags; + p.Parse(); + + NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); + visitor.Visit(p.CompilationUnit, null); + visitor.Cu.FileName = fileName; + visitor.Cu.ErrorsDuringCompile = p.Errors.count > 0; + RetrieveRegions(visitor.Cu, p.Lexer.SpecialTracker); + AddCommentTags(visitor.Cu, p.Lexer.TagComments); + return visitor.Cu; + } void AddCommentTags(ICompilationUnit cu, ArrayList tagComments) { diff --git a/src/Main/Base/Project/Src/Dom/IResolver.cs b/src/Main/Base/Project/Src/Dom/IResolver.cs index 36026e2fc4..188126b56b 100644 --- a/src/Main/Base/Project/Src/Dom/IResolver.cs +++ b/src/Main/Base/Project/Src/Dom/IResolver.cs @@ -3,7 +3,7 @@ * User: Omnibrain * Date: 30.11.2004 * Time: 23:23 - * + * * To change this template use Tools | Options | Coding | Edit Standard Headers. */ @@ -24,10 +24,11 @@ namespace ICSharpCode.SharpDevelop.Dom /// Resolves an expression. /// The caretLineNumber and caretColumn is 1 based. /// - ResolveResult Resolve(string expression, - int caretLineNumber, - int caretColumn, - string fileName); + ResolveResult Resolve(string expression, + int caretLineNumber, + int caretColumn, + string fileName, + string fileContent); ArrayList CtrlSpace(int caretLine, int caretColumn, string fileName); } diff --git a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs index 9d3b9d37bd..f26ea3ce63 100644 --- a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs +++ b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs @@ -96,7 +96,8 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver public ResolveResult Resolve(string expression, int caretLineNumber, int caretColumn, - string fileName) + string fileName, + string fileContent) { if (expression == null) { expression = ""; @@ -110,12 +111,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver if (parseInfo == null) { return null; } - ICSharpCode.NRefactory.Parser.AST.CompilationUnit fileCompilationUnit = parseInfo.MostRecentCompilationUnit.Tag as ICSharpCode.NRefactory.Parser.AST.CompilationUnit; - if (fileCompilationUnit == null) { -// ICSharpCode.NRefactory.Parser.Parser fileParser = new ICSharpCode.NRefactory.Parser.Parser(); -// fileParser.Parse(new Lexer(new StringReader(fileContent))); - return null; - } Expression expr = null; if (expression == "") { if ((expr = WithResolve()) == null) { @@ -125,7 +120,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver if (expr == null) { expr = SpecialConstructs(expression); if (expr == null) { - ICSharpCode.NRefactory.Parser.IParser p = ICSharpCode.NRefactory.Parser.ParserFactory.CreateParser(language, new System.IO.StringReader(expression)); + ICSharpCode.NRefactory.Parser.IParser p = ParserFactory.CreateParser(language, new System.IO.StringReader(expression)); expr = p.ParseExpression(); if (expr == null) { return null; @@ -133,17 +128,23 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } } lookupTableVisitor = new LookupTableVisitor(languageProperties.NameComparer); - lookupTableVisitor.Visit(fileCompilationUnit, null); - NRefactoryASTConvertVisitor cSharpVisitor = new NRefactoryASTConvertVisitor(parseInfo.MostRecentCompilationUnit != null ? parseInfo.MostRecentCompilationUnit.ProjectContent : null); - - cu = (ICompilationUnit)cSharpVisitor.Visit(fileCompilationUnit, null); + //NRefactoryASTConvertVisitor cSharpVisitor = new NRefactoryASTConvertVisitor(parseInfo.MostRecentCompilationUnit != null ? parseInfo.MostRecentCompilationUnit.ProjectContent : null); + cu = parseInfo.MostRecentCompilationUnit; //(ICompilationUnit)cSharpVisitor.Visit(fileCompilationUnit, null); if (cu != null) { callingClass = cu.GetInnermostClass(caretLine, caretColumn); cu.FileName = fileName; } callingMember = GetCurrentMember(); + if (callingMember != null) { + System.IO.TextReader content = ExtractMethod(fileContent, callingMember); + if (content != null) { + ICSharpCode.NRefactory.Parser.IParser p = ParserFactory.CreateParser(language, content); + p.Parse(); + lookupTableVisitor.Visit(p.CompilationUnit, null); + } + } TypeVisitor typeVisitor = new TypeVisitor(this); @@ -206,12 +207,71 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } return null; } - return new ResolveResult(callingClass, callingMember, FixType(type)); + return new ResolveResult(callingClass, callingMember, type); } - IReturnType FixType(IReturnType type) + /// + /// Creates a new class containing only the specified member. + /// This is useful because we only want to parse current method for local variables, + /// as all fields etc. are already prepared in the AST. + /// + System.IO.TextReader ExtractMethod(string fileContent, IMember member) { - return type; + // As the parse information is always some seconds old, the end line could be wrong + // if the user just inserted a line in the method. + // We can ignore that case because it is sufficient for the parser when the first part of the + // method body is ok. + // Since we are operating directly on the edited buffer, the parser might not be + // able to resolve invalid declarations. + // We can ignore even that because the 'invalid line' is the line the user is currently + // editing, and the declarations he is using are always above that line. + + + // The ExtractMethod-approach has the advantage that the method contents do not have + // do be parsed and stored in memory before they are needed. + // Previous SharpDevelop versions always stored the SharpRefactory[VB] parse tree as 'Tag' + // to the AST CompilationUnit. + // This approach doesn't need that, so one could even go and implement a special parser + // mode that does not parse the method bodies for the normal run (in the ParserUpdateThread or + // SolutionLoadThread). That could improve the parser's speed dramatically. + + if (member.Region == null) return null; + int startLine = member.Region.BeginLine; + if (startLine < 1) return null; + IRegion bodyRegion; + if (member is IMethod) { + bodyRegion = ((IMethod)member).BodyRegion; + } else if (member is IProperty) { + bodyRegion = ((IProperty)member).BodyRegion; + } else if (member is IIndexer) { + bodyRegion = ((IIndexer)member).BodyRegion; + } else if (member is IEvent) { + bodyRegion = ((IEvent)member).BodyRegion; + } else { + return null; + } + if (bodyRegion == null) return null; + int endLine = bodyRegion.EndLine; + int offset = 0; + for (int i = 0; i < startLine - 1; ++i) { // -1 because the startLine must be included + offset = fileContent.IndexOf('\n', offset) + 1; + if (offset <= 0) return null; + } + int startOffset = offset; + for (int i = startLine - 1; i < endLine; ++i) { + int newOffset = fileContent.IndexOf('\n', offset) + 1; + if (newOffset <= 0) break; + offset = newOffset; + } +// Console.WriteLine("", startLine, endLine); +// Console.Write(fileContent.Substring(startOffset, offset - startOffset)); +// Console.WriteLine(""); + int length = offset - startOffset; + System.Text.StringBuilder b = new System.Text.StringBuilder("class A {", length + 10 + startLine); + b.Append('\n', startLine - 1); + b.Append(fileContent, startOffset, length); + b.Append("}\n"); + return new System.IO.StringReader(b.ToString()); } #region Resolve Identifier @@ -225,12 +285,12 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver LocalLookupVariable var = SearchVariable(identifier); if (var != null) { IReturnType type = GetVariableType(var); - IField field = new DefaultField(FixType(type), identifier, ModifierEnum.None, new DefaultRegion(var.StartPos, var.EndPos), callingClass); + IField field = new DefaultField(type, identifier, ModifierEnum.None, new DefaultRegion(var.StartPos, var.EndPos), callingClass); return new LocalResolveResult(callingMember, field, false); } IParameter para = SearchMethodParameter(identifier); if (para != null) { - IField field = new DefaultField(FixType(para.ReturnType), para.Name, ModifierEnum.None, para.Region, callingClass); + IField field = new DefaultField(para.ReturnType, para.Name, ModifierEnum.None, para.Region, callingClass); return new LocalResolveResult(callingMember, field, true); } } @@ -263,7 +323,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver private ResolveResult CreateMemberResolveResult(IMember member) { - member.ReturnType = FixType(member.ReturnType); return new MemberResolveResult(callingClass, callingMember, member); } @@ -339,14 +398,19 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver { if (callingClass == null) return null; + foreach (IMethod method in callingClass.Methods) { + if (method.BodyRegion != null && method.BodyRegion.IsInside(caretLine, caretColumn)) { + return method; + } + } foreach (IProperty property in callingClass.Properties) { if (property.BodyRegion != null && property.BodyRegion.IsInside(caretLine, caretColumn)) { return property; } } - foreach (IMethod method in callingClass.Methods) { - if (method.BodyRegion != null && method.BodyRegion.IsInside(caretLine, caretColumn)) { - return method; + foreach (IIndexer indexer in callingClass.Indexer) { + if (indexer.BodyRegion != null && indexer.BodyRegion.IsInside(caretLine, caretColumn)) { + return indexer; } } return null; diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index 7fc617aa66..69396d6040 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -401,7 +401,7 @@ namespace ICSharpCode.Core //try { IParser parser = GetParser(fileName); if (parser != null) { - return parser.CreateResolver().Resolve(expression, caretLineNumber, caretColumn, fileName); + return parser.CreateResolver().Resolve(expression, caretLineNumber, caretColumn, fileName, fileContent); } return null; //} catch {