Browse Source

Even more performance improvements for the LoadSolutionProjectsThread. Fixed SkipCurrentBlock() in C# lexer.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@141 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
995de1838d
  1. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
  2. 3
      src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs
  3. 6
      src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs
  4. 3
      src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs
  5. 2
      src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs
  6. 4
      src/Libraries/NRefactory/Project/Src/Parser/IParser.cs
  7. 18
      src/Libraries/NRefactory/Test/Lexer/CSharp/LexerTest.cs
  8. 1
      src/Libraries/NRefactory/Test/NRefactoryTests.csproj
  9. 6
      src/Libraries/NRefactory/Test/Parser/ParseUtilCSharp.cs
  10. 71
      src/Libraries/NRefactory/Test/Parser/SkipMethodBodiesTest.cs
  11. 9
      src/Main/Base/Project/Src/Project/Items/ProjectItem.cs
  12. 44
      src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
  13. 23
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

2
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) ICompilationUnit Parse(ICSharpCode.NRefactory.Parser.IParser p, string fileName, IProjectContent projectContent)
{ {
p.Lexer.SpecialCommentTags = lexerTags; p.Lexer.SpecialCommentTags = lexerTags;
((ICSharpCode.NRefactory.Parser.AbstractParser)p).ParseMethodContents = false; p.ParseMethodBodies = false;
p.Parse(); p.Parse();
NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent); NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(projectContent);

3
src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs

@ -171,6 +171,9 @@ namespace ICSharpCode.NRefactory.Parser
/// <summary> /// <summary>
/// Skips to the end of the current code block. /// 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.
/// </summary> /// </summary>
public virtual void SkipCurrentBlock() public virtual void SkipCurrentBlock()
{ {

6
src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs

@ -805,13 +805,15 @@ namespace ICSharpCode.NRefactory.Parser.CSharp
/// <summary> /// <summary>
/// Skips to the end of the current code block. /// 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.
/// </summary> /// </summary>
public override void SkipCurrentBlock() public override void SkipCurrentBlock()
{ {
int braceCount = 0; int braceCount = 0;
Token t; Token t;
StartPeek(); while ((t = LookAhead).kind != Tokens.EOF) {
while ((t = Peek()).kind != Tokens.EOF) {
if (t.kind == Tokens.OpenCurlyBrace) { if (t.kind == Tokens.OpenCurlyBrace) {
++braceCount; ++braceCount;
} else if (t.kind == Tokens.CloseCurlyBrace) { } else if (t.kind == Tokens.CloseCurlyBrace) {

3
src/Libraries/NRefactory/Project/Src/Lexer/ILexer.cs

@ -70,6 +70,9 @@ namespace ICSharpCode.NRefactory.Parser
/// <summary> /// <summary>
/// Skips to the end of the current code block. /// 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.
/// </summary> /// </summary>
void SkipCurrentBlock(); void SkipCurrentBlock();
} }

2
src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.Parser
protected bool parseMethodContents = true; protected bool parseMethodContents = true;
public bool ParseMethodContents { public bool ParseMethodBodies {
get { get {
return parseMethodContents; return parseMethodContents;
} }

4
src/Libraries/NRefactory/Project/Src/Parser/IParser.cs

@ -29,6 +29,10 @@ namespace ICSharpCode.NRefactory.Parser
get; get;
} }
bool ParseMethodBodies {
get; set;
}
void Parse(); void Parse();
Expression ParseExpression(); Expression ParseExpression();

18
src/Libraries/NRefactory/Test/Lexer/CSharp/LexerTest.cs

@ -116,27 +116,35 @@ namespace ICSharpCode.NRefactory.Tests.Lexer.CSharp
[Test] [Test]
public void TestEmptyBlock() public void TestEmptyBlock()
{ {
ILexer lexer = GenerateLexer(new StringReader("{}")); ILexer lexer = GenerateLexer(new StringReader("{}+"));
Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind); Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind);
Assert.AreEqual(Tokens.CloseCurlyBrace, 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] [Test]
public void TestSkippedEmptyBlock() public void TestSkippedEmptyBlock()
{ {
ILexer lexer = GenerateLexer(new StringReader("{}")); ILexer lexer = GenerateLexer(new StringReader("{}+"));
Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind); Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind);
lexer.NextToken();
lexer.SkipCurrentBlock(); 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] [Test]
public void TestSkippedNonEmptyBlock() 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); Assert.AreEqual(Tokens.OpenCurlyBrace, lexer.NextToken().kind);
lexer.NextToken();
lexer.SkipCurrentBlock(); 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] [Test]

1
src/Libraries/NRefactory/Test/NRefactoryTests.csproj

@ -122,6 +122,7 @@
<Compile Include="Parser\Statements\YieldStatementTests.cs" /> <Compile Include="Parser\Statements\YieldStatementTests.cs" />
<Compile Include="Lexer\CSharp\NumberLexerTest.cs" /> <Compile Include="Lexer\CSharp\NumberLexerTest.cs" />
<Compile Include="Lexer\VBNet\LiteralsTests.cs" /> <Compile Include="Lexer\VBNet\LiteralsTests.cs" />
<Compile Include="Parser\SkipMethodBodiesTest.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="General\" /> <Folder Include="General\" />

6
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) 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)); IParser parser = ParserFactory.CreateParser(SupportedLanguages.CSharp, new StringReader(program));
parser.ParseMethodBodies = !skipMethodBodies;
parser.Parse(); parser.Parse();
Assert.IsNotNull(parser.Errors); Assert.IsNotNull(parser.Errors);
if (expectError) if (expectError)

71
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);
}
}
}

9
src/Main/Base/Project/Src/Project/Items/ProjectItem.cs

@ -47,6 +47,7 @@ namespace ICSharpCode.SharpDevelop.Project
} }
set { set {
project = value; project = value;
fileNameCache = null;
} }
} }
@ -57,6 +58,7 @@ namespace ICSharpCode.SharpDevelop.Project
} }
set { set {
include = value; include = value;
fileNameCache = null;
} }
} }
@ -67,12 +69,17 @@ namespace ICSharpCode.SharpDevelop.Project
} }
} }
string fileNameCache;
[Browsable(false)] [Browsable(false)]
public virtual string FileName { public virtual string FileName {
get { get {
return Path.Combine(project.Directory, Include); if (fileNameCache == null)
fileNameCache = Path.Combine(project.Directory, include);
return fileNameCache;
} }
set { set {
fileNameCache = null;
Include = FileUtility.GetRelativePath(project.Directory, value); Include = FileUtility.GetRelativePath(project.Directory, value);
} }
} }

44
src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs

@ -203,27 +203,61 @@ namespace ICSharpCode.Core
new AddReferenceDelegate(AddReference).BeginInvoke(e.ReferenceProjectItem, null, null); 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() internal void Initialize2()
{ {
if (!initializing) return; if (!initializing) return;
ProjectItem[] arr = project.Items.ToArray(); ProjectItem[] arr = project.Items.ToArray();
try { 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); 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) { 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) if ((i % 5) == 2)
StatusBarService.ProgressMonitor.WorkDone = i; StatusBarService.ProgressMonitor.WorkDone = i;
if (item.ItemType == ItemType.Compile) { if (item.ItemType == ItemType.Compile) {
ParseInformation parseInfo = ParserService.ParseFile(item.FileName, null, true, false); string fileName = item.FileName;
if (parseInfo != null) { string fileContent;
UpdateCompilationUnit(null, parseInfo.BestCompilationUnit as ICompilationUnit, item.FileName, true); 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; if (!initializing) return;
} }
} finally { } finally {
StatusBarService.ProgressMonitor.Done(); StatusBarService.ProgressMonitor.Done();
initializing = false; initializing = false;
getParseableContentEncoding = null;
} }
} }

23
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -251,17 +251,24 @@ namespace ICSharpCode.Core
static IProjectContent GetProjectContent(string fileName) static IProjectContent GetProjectContent(string fileName)
{ {
lock (projectContents) {
foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) { foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) {
if (projectContent.Key.IsFileInProject(fileName)) { if (projectContent.Key.IsFileInProject(fileName)) {
return projectContent.Value; return projectContent.Value;
} }
} }
}
return null; return null;
} }
static IProjectContent defaultProjectContent = new DefaultProjectContent(); static IProjectContent defaultProjectContent = new DefaultProjectContent();
public static ParseInformation ParseFile(string fileName, string fileContent, bool updateCommentTags, bool fireUpdate) 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); IParser parser = GetParser(fileName);
if (parser == null) { if (parser == null) {
@ -281,10 +288,14 @@ namespace ICSharpCode.Core
} }
} }
try { try {
IProjectContent fileProjectContent = GetProjectContent(fileName); if (fileProjectContent == null) {
// GetProjectContent is expensive because it compares all file names, so
// we accept the project content as optional parameter.
fileProjectContent = GetProjectContent(fileName);
if (fileProjectContent == null) { if (fileProjectContent == null) {
fileProjectContent = defaultProjectContent; fileProjectContent = defaultProjectContent;
} }
}
if (fileContent != null) { if (fileContent != null) {
parserOutput = parser.Parse(fileProjectContent, fileName, fileContent); parserOutput = parser.Parse(fileProjectContent, fileName, fileContent);
@ -295,17 +306,11 @@ namespace ICSharpCode.Core
parserOutput = parser.Parse(fileProjectContent, fileName); parserOutput = parser.Parse(fileProjectContent, fileName);
} }
lock (projectContents) {
foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) {
if (projectContent.Key.IsFileInProject(fileName)) {
if (parsings.ContainsKey(fileName)) { if (parsings.ContainsKey(fileName)) {
ParseInformation parseInformation = parsings[fileName]; ParseInformation parseInformation = parsings[fileName];
projectContent.Value.UpdateCompilationUnit(parseInformation.MostRecentCompilationUnit, parserOutput as ICompilationUnit, fileName, updateCommentTags); fileProjectContent.UpdateCompilationUnit(parseInformation.MostRecentCompilationUnit, parserOutput as ICompilationUnit, fileName, updateCommentTags);
} else { } else {
projectContent.Value.UpdateCompilationUnit(null, parserOutput, fileName, updateCommentTags); fileProjectContent.UpdateCompilationUnit(null, parserOutput, fileName, updateCommentTags);
}
}
}
} }
return UpdateParseInformation(parserOutput as ICompilationUnit, fileName, updateCommentTags, fireUpdate); return UpdateParseInformation(parserOutput as ICompilationUnit, fileName, updateCommentTags, fireUpdate);
} catch (Exception e) { } catch (Exception e) {

Loading…
Cancel
Save