diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
index 7033d5598e..7b428e9790 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
@@ -95,7 +95,7 @@ namespace CSharpBinding.Parser
ICompilationUnit Parse(ICSharpCode.NRefactory.Parser.IParser p, string fileName, IProjectContent projectContent)
{
p.Lexer.SpecialCommentTags = lexerTags;
- ((ICSharpCode.NRefactory.Parser.AbstractParser)p).ParseMethodContents = false;
+ p.ParseMethodBodies = false;
p.Parse();
NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent);
diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs
index 961cc7cdd9..a3eea8f723 100644
--- a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs
+++ b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs
@@ -171,6 +171,9 @@ namespace ICSharpCode.NRefactory.Parser
///
/// Skips to the end of the current code block.
+ /// For this, the lexer must have read the next token AFTER the token opening the
+ /// block (so that Lexer.Token is the block-opening token, not Lexer.LookAhead).
+ /// After the call, Lexer.LookAhead will be the block-closing token.
///
public virtual void SkipCurrentBlock()
{
diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs
index 68adba8a15..78e53d48e8 100644
--- a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs
+++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs
@@ -805,13 +805,15 @@ namespace ICSharpCode.NRefactory.Parser.CSharp
///
/// Skips to the end of the current code block.
+ /// For this, the lexer must have read the next token AFTER the token opening the
+ /// block (so that Lexer.Token is the block-opening token, not Lexer.LookAhead).
+ /// After the call, Lexer.LookAhead will be the block-closing token.
///
public override void SkipCurrentBlock()
{
int braceCount = 0;
Token t;
- StartPeek();
- while ((t = Peek()).kind != Tokens.EOF) {
+ while ((t = LookAhead).kind != Tokens.EOF) {
if (t.kind == Tokens.OpenCurlyBrace) {
++braceCount;
} else if (t.kind == Tokens.CloseCurlyBrace) {
diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs
index e074842173..d76e128c82 100644
--- a/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs
+++ b/src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs
@@ -70,6 +70,9 @@ namespace ICSharpCode.NRefactory.Parser
///
/// Skips to the end of the current code block.
+ /// For this, the lexer must have read the next token AFTER the token opening the
+ /// block (so that Lexer.Token is the block-opening token, not Lexer.LookAhead).
+ /// After the call, Lexer.LookAhead will be the block-closing token.
///
void SkipCurrentBlock();
}
diff --git a/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs b/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs
index 6fc4731072..d2fbb63b28 100644
--- a/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs
+++ b/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs
@@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.Parser
protected bool parseMethodContents = true;
- public bool ParseMethodContents {
+ public bool ParseMethodBodies {
get {
return parseMethodContents;
}
diff --git a/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs b/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs
index 436b5d2148..e1d45bcc97 100644
--- a/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs
+++ b/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs
@@ -29,6 +29,10 @@ namespace ICSharpCode.NRefactory.Parser
get;
}
+ bool ParseMethodBodies {
+ get; set;
+ }
+
void Parse();
Expression ParseExpression();
diff --git a/src/Libraries/NRefactory/Test/Lexer/CSharp/LexerTest.cs b/src/Libraries/NRefactory/Test/Lexer/CSharp/LexerTest.cs
index 5e02318e8c..e475f36278 100644
--- a/src/Libraries/NRefactory/Test/Lexer/CSharp/LexerTest.cs
+++ b/src/Libraries/NRefactory/Test/Lexer/CSharp/LexerTest.cs
@@ -116,29 +116,37 @@ namespace ICSharpCode.NRefactory.Tests.Lexer.CSharp
[Test]
public void TestEmptyBlock()
{
- ILexer lexer = GenerateLexer(new StringReader("{}"));
+ ILexer lexer = GenerateLexer(new StringReader("{}+"));
Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind);
Assert.AreEqual(Tokens.CloseCurlyBrace, lexer.NextToken().kind);
+ Assert.AreEqual(Tokens.Plus, lexer.NextToken().kind);
+ Assert.AreEqual(Tokens.EOF, lexer.NextToken().kind);
}
[Test]
public void TestSkippedEmptyBlock()
{
- ILexer lexer = GenerateLexer(new StringReader("{}"));
+ ILexer lexer = GenerateLexer(new StringReader("{}+"));
Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind);
+ lexer.NextToken();
lexer.SkipCurrentBlock();
- Assert.AreEqual(Tokens.CloseCurlyBrace, lexer.NextToken().kind);
+ Assert.AreEqual(Tokens.CloseCurlyBrace, lexer.LookAhead.kind);
+ Assert.AreEqual(Tokens.Plus, lexer.NextToken().kind);
+ Assert.AreEqual(Tokens.EOF, lexer.NextToken().kind);
}
[Test]
public void TestSkippedNonEmptyBlock()
{
- ILexer lexer = GenerateLexer(new StringReader("{ TestMethod('}'); /* }}} */ break; }"));
+ ILexer lexer = GenerateLexer(new StringReader("{ TestMethod('}'); /* }}} */ while(1) {break;} }+"));
Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind);
+ lexer.NextToken();
lexer.SkipCurrentBlock();
- Assert.AreEqual(Tokens.CloseCurlyBrace, lexer.NextToken().kind);
+ Assert.AreEqual(Tokens.CloseCurlyBrace, lexer.LookAhead.kind);
+ Assert.AreEqual(Tokens.Plus, lexer.NextToken().kind);
+ Assert.AreEqual(Tokens.EOF, lexer.NextToken().kind);
}
-
+
[Test]
public void TestOpenSquareBracket()
{
diff --git a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj
index 2c1c80a1b5..eeb7979b86 100644
--- a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj
+++ b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj
@@ -122,6 +122,7 @@
+
diff --git a/src/Libraries/NRefactory/Test/Parser/ParseUtilCSharp.cs b/src/Libraries/NRefactory/Test/Parser/ParseUtilCSharp.cs
index 7939443d68..d13f28c477 100644
--- a/src/Libraries/NRefactory/Test/Parser/ParseUtilCSharp.cs
+++ b/src/Libraries/NRefactory/Test/Parser/ParseUtilCSharp.cs
@@ -26,8 +26,14 @@ namespace ICSharpCode.NRefactory.Tests.AST
}
public static object ParseGlobal(string program, Type type, bool expectError)
+ {
+ return ParseGlobal(program, type, expectError, false);
+ }
+
+ public static object ParseGlobal(string program, Type type, bool expectError, bool skipMethodBodies)
{
IParser parser = ParserFactory.CreateParser(SupportedLanguages.CSharp, new StringReader(program));
+ parser.ParseMethodBodies = !skipMethodBodies;
parser.Parse();
Assert.IsNotNull(parser.Errors);
if (expectError)
diff --git a/src/Libraries/NRefactory/Test/Parser/SkipMethodBodiesTest.cs b/src/Libraries/NRefactory/Test/Parser/SkipMethodBodiesTest.cs
new file mode 100644
index 0000000000..67c7f2e321
--- /dev/null
+++ b/src/Libraries/NRefactory/Test/Parser/SkipMethodBodiesTest.cs
@@ -0,0 +1,71 @@
+/*
+ * Created by SharpDevelop.
+ * User: Daniel Grunwald
+ * Date: 11.05.2005
+ * Time: 16:37
+ *
+ * To change this template use Tools | Options | Coding | Edit Standard Headers.
+ */
+
+using System;
+using System.Drawing;
+using System.IO;
+
+using NUnit.Framework;
+
+using ICSharpCode.NRefactory.Parser;
+using ICSharpCode.NRefactory.Parser.AST;
+
+namespace ICSharpCode.NRefactory.Tests.AST
+{
+ [TestFixture]
+ public class SkipMethodBodiesTest
+ {
+ [Test]
+ public void EmptyMethods()
+ {
+ string txt = @"internal sealed class Lexer : AbstractLexer
+ {
+ public Lexer(TextReader reader) : base(reader)
+ {
+ }
+
+ void Method()
+ {
+ }
+ }";
+ Check((TypeDeclaration)ParseUtilCSharp.ParseGlobal(txt, typeof(TypeDeclaration), false, true));
+ }
+
+ [Test]
+ public void NonEmptyMethods()
+ {
+ string txt = @"internal sealed class Lexer : AbstractLexer
+ {
+ public Lexer(TextReader reader) : base(reader)
+ {
+ if (reader == null) {
+ throw new ArgumentNullException(""reader"");
+ }
+ }
+
+ void Method()
+ {
+ while(something) {
+ if (anything)
+ break;
+ }
+ }
+ }";
+ Check((TypeDeclaration)ParseUtilCSharp.ParseGlobal(txt, typeof(TypeDeclaration), false, true));
+ }
+
+ void Check(TypeDeclaration td)
+ {
+ Assert.AreEqual("Lexer", td.Name);
+ Assert.AreEqual(2, td.Children.Count);
+ Assert.AreEqual(0, ((ConstructorDeclaration)td.Children[0]).Body.Children.Count);
+ Assert.AreEqual(0, ((MethodDeclaration)td.Children[1]).Body.Children.Count);
+ }
+ }
+}
diff --git a/src/Main/Base/Project/Src/Project/Items/ProjectItem.cs b/src/Main/Base/Project/Src/Project/Items/ProjectItem.cs
index 35b87afb4b..9e19b36b4e 100644
--- a/src/Main/Base/Project/Src/Project/Items/ProjectItem.cs
+++ b/src/Main/Base/Project/Src/Project/Items/ProjectItem.cs
@@ -47,6 +47,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
set {
project = value;
+ fileNameCache = null;
}
}
@@ -57,6 +58,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
set {
include = value;
+ fileNameCache = null;
}
}
@@ -67,12 +69,17 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
+ string fileNameCache;
+
[Browsable(false)]
public virtual string FileName {
get {
- return Path.Combine(project.Directory, Include);
+ if (fileNameCache == null)
+ fileNameCache = Path.Combine(project.Directory, include);
+ return fileNameCache;
}
set {
+ fileNameCache = null;
Include = FileUtility.GetRelativePath(project.Directory, value);
}
}
diff --git a/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
index cc9218eee7..4ae1d1fa6d 100644
--- a/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
+++ b/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
@@ -203,27 +203,61 @@ namespace ICSharpCode.Core
new AddReferenceDelegate(AddReference).BeginInvoke(e.ReferenceProjectItem, null, null);
}
+ delegate string GetParseableContentDelegate(string fileName);
+
+ Encoding getParseableContentEncoding;
+
+ string GetParseableFileContent(string fileName)
+ {
+ // Loading the source files is done asynchronously:
+ // While one file is parsed, the next is already loaded from disk.
+ string res = project.GetParseableFileContent(fileName);
+ if (res != null)
+ return res;
+ // load file
+ using (StreamReader r = new StreamReader(fileName, getParseableContentEncoding)) {
+ return r.ReadToEnd();
+ }
+ }
+
internal void Initialize2()
{
if (!initializing) return;
ProjectItem[] arr = project.Items.ToArray();
try {
+ Properties textEditorProperties = ((Properties)PropertyService.Get("ICSharpCode.TextEditor.Document.Document.DefaultDocumentAggregatorProperties", new Properties()));
+ getParseableContentEncoding = Encoding.GetEncoding(textEditorProperties.Get("Encoding", 1252));
+ textEditorProperties = null;
+
StatusBarService.ProgressMonitor.BeginTask("Parsing " + project.Name + "...", arr.Length);
+ GetParseableContentDelegate pcd = new GetParseableContentDelegate(GetParseableFileContent);
+ ProjectItem item;
+ ProjectItem nextItem = arr[0];
+ IAsyncResult res = null;
for (int i = 0; i < arr.Length; ++i) {
- ProjectItem item = arr[i];
+ item = nextItem;
+ nextItem = (i < arr.Length - 1) ? arr[i + 1] : null;
if ((i % 5) == 2)
StatusBarService.ProgressMonitor.WorkDone = i;
if (item.ItemType == ItemType.Compile) {
- ParseInformation parseInfo = ParserService.ParseFile(item.FileName, null, true, false);
- if (parseInfo != null) {
- UpdateCompilationUnit(null, parseInfo.BestCompilationUnit as ICompilationUnit, item.FileName, true);
- }
+ string fileName = item.FileName;
+ string fileContent;
+ if (res != null)
+ fileContent = pcd.EndInvoke(res);
+ else
+ fileContent = GetParseableFileContent(fileName);
+ if (nextItem != null && nextItem.ItemType == ItemType.Compile)
+ res = pcd.BeginInvoke(nextItem.FileName, null, null);
+ else
+ res = null;
+ ParserService.ParseFile(this, fileName, fileContent, true, false);
}
if (!initializing) return;
}
} finally {
StatusBarService.ProgressMonitor.Done();
initializing = false;
+ getParseableContentEncoding = null;
}
}
diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
index 69396d6040..98c30676eb 100644
--- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
+++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
@@ -251,9 +251,11 @@ namespace ICSharpCode.Core
static IProjectContent GetProjectContent(string fileName)
{
- foreach (KeyValuePair projectContent in projectContents) {
- if (projectContent.Key.IsFileInProject(fileName)) {
- return projectContent.Value;
+ lock (projectContents) {
+ foreach (KeyValuePair projectContent in projectContents) {
+ if (projectContent.Key.IsFileInProject(fileName)) {
+ return projectContent.Value;
+ }
}
}
return null;
@@ -262,6 +264,11 @@ namespace ICSharpCode.Core
static IProjectContent defaultProjectContent = new DefaultProjectContent();
public static ParseInformation ParseFile(string fileName, string fileContent, bool updateCommentTags, bool fireUpdate)
+ {
+ return ParseFile(null, fileName, fileContent, updateCommentTags, fireUpdate);
+ }
+
+ public static ParseInformation ParseFile(IProjectContent fileProjectContent, string fileName, string fileContent, bool updateCommentTags, bool fireUpdate)
{
IParser parser = GetParser(fileName);
if (parser == null) {
@@ -281,9 +288,13 @@ namespace ICSharpCode.Core
}
}
try {
- IProjectContent fileProjectContent = GetProjectContent(fileName);
if (fileProjectContent == null) {
- fileProjectContent = defaultProjectContent;
+ // GetProjectContent is expensive because it compares all file names, so
+ // we accept the project content as optional parameter.
+ fileProjectContent = GetProjectContent(fileName);
+ if (fileProjectContent == null) {
+ fileProjectContent = defaultProjectContent;
+ }
}
if (fileContent != null) {
@@ -295,17 +306,11 @@ namespace ICSharpCode.Core
parserOutput = parser.Parse(fileProjectContent, fileName);
}
- lock (projectContents) {
- foreach (KeyValuePair projectContent in projectContents) {
- if (projectContent.Key.IsFileInProject(fileName)) {
- if (parsings.ContainsKey(fileName)) {
- ParseInformation parseInformation = parsings[fileName];
- projectContent.Value.UpdateCompilationUnit(parseInformation.MostRecentCompilationUnit, parserOutput as ICompilationUnit, fileName, updateCommentTags);
- } else {
- projectContent.Value.UpdateCompilationUnit(null, parserOutput, fileName, updateCommentTags);
- }
- }
- }
+ if (parsings.ContainsKey(fileName)) {
+ ParseInformation parseInformation = parsings[fileName];
+ fileProjectContent.UpdateCompilationUnit(parseInformation.MostRecentCompilationUnit, parserOutput as ICompilationUnit, fileName, updateCommentTags);
+ } else {
+ fileProjectContent.UpdateCompilationUnit(null, parserOutput, fileName, updateCommentTags);
}
return UpdateParseInformation(parserOutput as ICompilationUnit, fileName, updateCommentTags, fireUpdate);
} catch (Exception e) {