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. 20
      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. 37
      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 @@ -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);

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

@ -171,6 +171,9 @@ namespace ICSharpCode.NRefactory.Parser @@ -171,6 +171,9 @@ namespace ICSharpCode.NRefactory.Parser
/// <summary>
/// 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>
public virtual void SkipCurrentBlock()
{

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

@ -805,13 +805,15 @@ namespace ICSharpCode.NRefactory.Parser.CSharp @@ -805,13 +805,15 @@ namespace ICSharpCode.NRefactory.Parser.CSharp
/// <summary>
/// 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>
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) {

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

@ -70,6 +70,9 @@ namespace ICSharpCode.NRefactory.Parser @@ -70,6 +70,9 @@ namespace ICSharpCode.NRefactory.Parser
/// <summary>
/// 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>
void SkipCurrentBlock();
}

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

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

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

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

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

@ -116,29 +116,37 @@ namespace ICSharpCode.NRefactory.Tests.Lexer.CSharp @@ -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()
{

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

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

6
src/Libraries/NRefactory/Test/Parser/ParseUtilCSharp.cs

@ -26,8 +26,14 @@ namespace ICSharpCode.NRefactory.Tests.AST @@ -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)

71
src/Libraries/NRefactory/Test/Parser/SkipMethodBodiesTest.cs

@ -0,0 +1,71 @@ @@ -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 @@ -47,6 +47,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
set {
project = value;
fileNameCache = null;
}
}
@ -57,6 +58,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -57,6 +58,7 @@ namespace ICSharpCode.SharpDevelop.Project
}
set {
include = value;
fileNameCache = null;
}
}
@ -67,12 +69,17 @@ namespace ICSharpCode.SharpDevelop.Project @@ -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);
}
}

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

@ -203,27 +203,61 @@ namespace ICSharpCode.Core @@ -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;
}
}

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

@ -251,9 +251,11 @@ namespace ICSharpCode.Core @@ -251,9 +251,11 @@ namespace ICSharpCode.Core
static IProjectContent GetProjectContent(string fileName)
{
foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) {
if (projectContent.Key.IsFileInProject(fileName)) {
return projectContent.Value;
lock (projectContents) {
foreach (KeyValuePair<IProject, IProjectContent> projectContent in projectContents) {
if (projectContent.Key.IsFileInProject(fileName)) {
return projectContent.Value;
}
}
}
return null;
@ -262,6 +264,11 @@ namespace ICSharpCode.Core @@ -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 @@ -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 @@ -295,17 +306,11 @@ namespace ICSharpCode.Core
parserOutput = parser.Parse(fileProjectContent, fileName);
}
lock (projectContents) {
foreach (KeyValuePair<IProject, IProjectContent> 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) {

Loading…
Cancel
Save