jkuehner 11 years ago
parent
commit
90f3fc3fe0
  1. 6
      src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsReader.cs
  2. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
  3. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  4. 280
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs
  5. 253
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs
  6. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs
  7. 49
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs
  8. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs
  9. 3
      src/AddIns/Debugger/Debugger.AddIn/Breakpoints/BreakpointEditorPopup.xaml.cs
  10. 18
      src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs
  11. 5
      src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs
  12. 156
      src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs
  13. 2
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  14. 3
      src/AddIns/VersionControl/GitAddIn/Src/Git.cs
  15. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/UseOfMemberOfNullReference.cs
  16. 3
      src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeViewItem.cs
  17. 12
      src/Main/Base/Project/Parser/ProjectContentContainer.cs
  18. 2
      src/Main/Base/Project/Src/Project/AbstractProject.cs
  19. 2
      src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs
  20. 5
      src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs
  21. 8
      src/Main/SharpDevelop/Parser/ParserService.cs
  22. 96
      src/Main/SharpDevelop/Parser/ParserServiceEntry.cs
  23. 12
      src/Tools/StressTest/StressTest.sln
  24. 3
      src/Tools/StressTest/StressTest/StressTest.csproj
  25. 1
      src/Tools/StressTest/StressTest/UserControl.xaml.cs

6
src/AddIns/Analysis/UnitTesting/TestRunner/TestResultsReader.cs

@ -61,8 +61,10 @@ namespace ICSharpCode.UnitTesting @@ -61,8 +61,10 @@ namespace ICSharpCode.UnitTesting
public void Dispose()
{
reader.Dispose();
namedPipe.Dispose();
if (reader != null)
reader.Dispose();
if (namedPipe != null)
namedPipe.Dispose();
}
public event EventHandler<TestFinishedEventArgs> TestFinished;

1
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin

@ -363,7 +363,6 @@ @@ -363,7 +363,6 @@
<Class class = "ICSharpCode.NRefactory.CSharp.Refactoring.UseIsOperatorIssue" />
<Class class = "ICSharpCode.NRefactory.CSharp.Refactoring.UseMethodAnyIssue" />
<Class class = "ICSharpCode.NRefactory.CSharp.Refactoring.UseMethodIsInstanceOfTypeIssue" />
<Class class = "ICSharpCode.NRefactory.CSharp.Refactoring.UseOfMemberOfNullReference" />
<Class class = "ICSharpCode.NRefactory.CSharp.Refactoring.ValueParameterNotUsedIssue" />
<Class class = "ICSharpCode.NRefactory.CSharp.Refactoring.XmlDocIssue" />
</Path>

1
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -91,6 +91,7 @@ @@ -91,6 +91,7 @@
<Compile Include="Src\CSharpSemanticHighlighterVisitor.cs">
<DependentUpon>CSharpSemanticHighlighter.cs</DependentUpon>
</Compile>
<Compile Include="Src\CSharpTextEditorExtension.cs" />
<Compile Include="Src\FormattingStrategy\CSharpFormattingOptionsContainer.cs" />
<Compile Include="Src\FormattingStrategy\CSharpFormatter.cs" />
<Compile Include="Src\FormattingStrategy\CSharpFormattingPolicies.cs" />

280
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs

@ -20,13 +20,18 @@ using System; @@ -20,13 +20,18 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.SharpDevelop.Project;
using CSharpBinding.Completion;
using CSharpBinding.FormattingStrategy;
using CSharpBinding.Refactoring;
@ -50,223 +55,98 @@ namespace CSharpBinding @@ -50,223 +55,98 @@ namespace CSharpBinding
this.container.AddService(typeof(System.CodeDom.Compiler.CodeDomProvider), new Microsoft.CSharp.CSharpCodeProvider());
}
public override ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ICSharpCode.NRefactory.Editor.ITextSource fileContent)
public override ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
return new CSharpCompletionBinding(fileName, currentLocation, fileContent);
}
}
public class CSharpTextEditorExtension : ITextEditorExtension
{
ITextEditor editor;
IssueManager inspectionManager;
IList<IContextActionProvider> contextActionProviders;
CodeManipulation codeManipulation;
CaretReferenceHighlightRenderer renderer;
CodeEditorFormattingOptionsAdapter options;
TextEditorOptions originalEditorOptions;
public void Attach(ITextEditor editor)
{
this.editor = editor;
inspectionManager = new IssueManager(editor);
codeManipulation = new CodeManipulation(editor);
renderer = new CaretReferenceHighlightRenderer(editor);
// Patch editor options (indentation) to project-specific settings
if (!editor.ContextActionProviders.IsReadOnly) {
contextActionProviders = AddInTree.BuildItems<IContextActionProvider>("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null);
editor.ContextActionProviders.AddRange(contextActionProviders);
}
// Create instance of options adapter and register it as service
var formattingPolicy = CSharpFormattingPolicies.Instance.GetProjectOptions(
SD.ProjectService.FindProjectContainingFile(editor.FileName));
var textEditor = editor.GetService<TextEditor>();
if (textEditor != null) {
options = new CodeEditorFormattingOptionsAdapter(textEditor.Options, editor.Options, formattingPolicy.OptionsContainer);
var textViewServices = textEditor.TextArea.TextView.Services;
// Unregister any previous ITextEditorOptions instance from editor, if existing, register our impl.
textViewServices.RemoveService(typeof(ITextEditorOptions));
textViewServices.AddService(typeof(ITextEditorOptions), options);
// Set TextEditor's options to same object
originalEditorOptions = textEditor.Options;
textEditor.Options = options.TextEditorOptions;
}
if (context == null)
throw new ArgumentNullException("context");
string content = GeneratePartialClassContextStub(fileName, location, context);
const string caretPoint = "$__Caret_Point__$;";
int caretOffset = content.IndexOf(caretPoint, StringComparison.Ordinal) + expressionToComplete.Length;
SD.Log.DebugFormatted("context used for dot completion: {0}", content.Replace(caretPoint, "$" + expressionToComplete + "|$"));
var doc = new ReadOnlyDocument(content.Replace(caretPoint, expressionToComplete));
return new CSharpCompletionBinding(fileName, doc.GetLocation(caretOffset), doc.CreateSnapshot());
}
public void Detach()
static string GeneratePartialClassContextStub(FileName fileName, TextLocation location, ICodeContext context)
{
var textEditor = editor.GetService<TextEditor>();
if (textEditor != null) {
var textView = textEditor.TextArea.TextView;
// Unregister our ITextEditorOptions instance from editor
var optionsService = textView.GetService<ITextEditorOptions>();
if ((optionsService != null) && (optionsService == options))
textView.Services.RemoveService(typeof(ITextEditorOptions));
// Reset TextEditor options, too?
if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions))
textEditor.Options = originalEditorOptions;
}
codeManipulation.Dispose();
if (inspectionManager != null) {
inspectionManager.Dispose();
inspectionManager = null;
}
if (contextActionProviders != null) {
editor.ContextActionProviders.RemoveAll(contextActionProviders.Contains);
var compilation = SD.ParserService.GetCompilationForFile(fileName);
var file = SD.ParserService.GetExistingUnresolvedFile(fileName);
if (compilation == null || file == null)
return "";
var unresolvedMember = file.GetMember(location);
if (unresolvedMember == null)
return "";
var member = unresolvedMember.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly));
if (member == null)
return "";
var builder = new TypeSystemAstBuilder();
MethodDeclaration decl;
if (unresolvedMember is IMethod) {
// If it's a method, convert it directly (including parameters + type parameters)
decl = (MethodDeclaration)builder.ConvertEntity(member);
} else {
// Otherwise, create a method anyways, and copy the parameters
decl = new MethodDeclaration();
if (member is IParameterizedMember) {
foreach (var p in ((IParameterizedMember)member).Parameters) {
decl.Parameters.Add(builder.ConvertParameter(p));
}
}
}
renderer.Dispose();
options = null;
this.editor = null;
}
}
class CodeEditorFormattingOptionsAdapter : ITextEditorOptions, INotifyPropertyChanged
{
CSharpFormattingOptionsContainer container;
readonly TextEditorOptions avalonEditOptions;
readonly TextEditorOptions originalAvalonEditOptions;
readonly ITextEditorOptions originalSDOptions;
public CodeEditorFormattingOptionsAdapter(TextEditorOptions originalAvalonEditOptions, ITextEditorOptions originalSDOptions, CSharpFormattingOptionsContainer container)
{
if (originalAvalonEditOptions == null)
throw new ArgumentNullException("originalAvalonEditOptions");
if (originalSDOptions == null)
throw new ArgumentNullException("originalSDOptions");
if (container == null)
throw new ArgumentNullException("container");
this.originalAvalonEditOptions = originalAvalonEditOptions;
this.avalonEditOptions = new TextEditorOptions(originalAvalonEditOptions);
this.originalSDOptions = originalSDOptions;
this.container = container;
// Update overridden options once
UpdateOverriddenProperties();
CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += OnFormattingPolicyUpdated;
this.originalAvalonEditOptions.PropertyChanged += OnOrigAvalonOptionsPropertyChanged;
this.originalSDOptions.PropertyChanged += OnSDOptionsPropertyChanged;
}
void OnFormattingPolicyUpdated(object sender, CSharpBinding.FormattingStrategy.CSharpFormattingPolicyUpdateEventArgs e)
{
// Update editor options from changed policy
UpdateOverriddenProperties();
OnPropertyChanged("IndentationSize");
OnPropertyChanged("IndentationString");
OnPropertyChanged("ConvertTabsToSpaces");
decl.Name = "__DebuggerStub__";
decl.ReturnType = builder.ConvertType(member.ReturnType);
decl.Modifiers = unresolvedMember.IsStatic ? Modifiers.Static : Modifiers.None;
// Make the method look like an explicit interface implementation so that it doesn't appear in CC
decl.PrivateImplementationType = new SimpleType("__DummyType__");
decl.Body = GenerateBodyFromContext(builder, context.LocalVariables.ToArray());
return WrapInType(unresolvedMember.DeclaringTypeDefinition, decl).ToString();
}
void UpdateOverriddenProperties()
static BlockStatement GenerateBodyFromContext(TypeSystemAstBuilder builder, IVariable[] variables)
{
avalonEditOptions.IndentationSize = container.GetEffectiveIndentationSize() ?? originalSDOptions.IndentationSize;
avalonEditOptions.ConvertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces() ?? originalSDOptions.ConvertTabsToSpaces;
var body = new BlockStatement();
foreach (var v in variables)
body.Statements.Add(new VariableDeclarationStatement(builder.ConvertType(v.Type), v.Name));
body.Statements.Add(new ExpressionStatement(new IdentifierExpression("$__Caret_Point__$")));
return body;
}
void OnOrigAvalonOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
static AstNode WrapInType(IUnresolvedTypeDefinition entity, EntityDeclaration decl)
{
if ((e.PropertyName != "IndentationSize") && (e.PropertyName != "IndentationString") && (e.PropertyName != "ConvertTabsToSpaces")) {
// Update values in our own TextEditorOptions instance
PropertyInfo propertyInfo = typeof(TextEditorOptions).GetProperty(e.PropertyName);
if (propertyInfo != null) {
propertyInfo.SetValue(avalonEditOptions, propertyInfo.GetValue(originalAvalonEditOptions));
if (entity == null)
return decl;
// Wrap decl in TypeDeclaration
decl = new TypeDeclaration {
ClassType = GetClassType(entity),
Modifiers = Modifiers.Partial,
Name = entity.Name,
Members = { decl }
};
if (entity.DeclaringTypeDefinition != null) {
// Handle nested types
return WrapInType(entity.DeclaringTypeDefinition, decl);
}
if (string.IsNullOrEmpty(entity.Namespace))
return decl;
return new NamespaceDeclaration(entity.Namespace) {
Members = {
decl
}
} else {
UpdateOverriddenProperties();
}
OnPropertyChanged(e.PropertyName);
};
}
void OnSDOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
OnPropertyChanged(e.PropertyName);
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public TextEditorOptions TextEditorOptions
static ClassType GetClassType(IUnresolvedTypeDefinition entity)
{
get {
return avalonEditOptions;
}
}
#region Overridden properties
public int IndentationSize {
get {
// Get value from own TextEditorOptions instance
return avalonEditOptions.IndentationSize;
}
}
public string IndentationString {
get {
// Get value from own TextEditorOptions instance
return avalonEditOptions.IndentationString;
}
}
public bool ConvertTabsToSpaces {
get {
// Get value from own TextEditorOptions instance
return avalonEditOptions.ConvertTabsToSpaces;
}
}
#endregion
#region Rest of ITextEditorOptions implementation
public bool AutoInsertBlockEnd {
get {
return originalSDOptions.AutoInsertBlockEnd;
}
}
public int VerticalRulerColumn {
get {
return originalSDOptions.VerticalRulerColumn;
switch (entity.Kind) {
case TypeKind.Interface:
return ClassType.Interface;
case TypeKind.Struct:
return ClassType.Struct;
default:
return ClassType.Class;
}
}
public bool UnderlineErrors {
get {
return originalSDOptions.UnderlineErrors;
}
}
public string FontFamily {
get {
return originalSDOptions.FontFamily;
}
}
public double FontSize {
get {
return originalSDOptions.FontSize;
}
}
#endregion
}
}

253
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs

@ -0,0 +1,253 @@ @@ -0,0 +1,253 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using ICSharpCode.AvalonEdit;
using CSharpBinding.FormattingStrategy;
using CSharpBinding.Refactoring;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Refactoring;
namespace CSharpBinding
{
public class CSharpTextEditorExtension : ITextEditorExtension
{
ITextEditor editor;
IssueManager inspectionManager;
IList<IContextActionProvider> contextActionProviders;
CodeManipulation codeManipulation;
CaretReferenceHighlightRenderer renderer;
CodeEditorFormattingOptionsAdapter options;
TextEditorOptions originalEditorOptions;
public void Attach(ITextEditor editor)
{
this.editor = editor;
inspectionManager = new IssueManager(editor);
codeManipulation = new CodeManipulation(editor);
renderer = new CaretReferenceHighlightRenderer(editor);
// Patch editor options (indentation) to project-specific settings
if (!editor.ContextActionProviders.IsReadOnly) {
contextActionProviders = AddInTree.BuildItems<IContextActionProvider>("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null);
editor.ContextActionProviders.AddRange(contextActionProviders);
}
// Create instance of options adapter and register it as service
var formattingPolicy = CSharpFormattingPolicies.Instance.GetProjectOptions(SD.ProjectService.FindProjectContainingFile(editor.FileName));
var textEditor = editor.GetService<TextEditor>();
if (textEditor != null) {
options = new CodeEditorFormattingOptionsAdapter(textEditor.Options, editor.Options, formattingPolicy.OptionsContainer);
var textViewServices = textEditor.TextArea.TextView.Services;
// Unregister any previous ITextEditorOptions instance from editor, if existing, register our impl.
textViewServices.RemoveService(typeof(ITextEditorOptions));
textViewServices.AddService(typeof(ITextEditorOptions), options);
// Set TextEditor's options to same object
originalEditorOptions = textEditor.Options;
textEditor.Options = options.TextEditorOptions;
}
}
public void Detach()
{
var textEditor = editor.GetService<TextEditor>();
if (textEditor != null) {
var textView = textEditor.TextArea.TextView;
// Unregister our ITextEditorOptions instance from editor
var optionsService = textView.GetService<ITextEditorOptions>();
if ((optionsService != null) && (optionsService == options))
textView.Services.RemoveService(typeof(ITextEditorOptions));
// Reset TextEditor options, too?
if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions))
textEditor.Options = originalEditorOptions;
}
codeManipulation.Dispose();
if (inspectionManager != null) {
inspectionManager.Dispose();
inspectionManager = null;
}
if (contextActionProviders != null) {
editor.ContextActionProviders.RemoveAll(contextActionProviders.Contains);
}
renderer.Dispose();
options = null;
this.editor = null;
}
}
class CodeEditorFormattingOptionsAdapter : ITextEditorOptions, INotifyPropertyChanged
{
CSharpFormattingOptionsContainer container;
readonly TextEditorOptions avalonEditOptions;
readonly TextEditorOptions originalAvalonEditOptions;
readonly ITextEditorOptions originalSDOptions;
public CodeEditorFormattingOptionsAdapter(TextEditorOptions originalAvalonEditOptions, ITextEditorOptions originalSDOptions, CSharpFormattingOptionsContainer container)
{
if (originalAvalonEditOptions == null)
throw new ArgumentNullException("originalAvalonEditOptions");
if (originalSDOptions == null)
throw new ArgumentNullException("originalSDOptions");
if (container == null)
throw new ArgumentNullException("container");
this.originalAvalonEditOptions = originalAvalonEditOptions;
this.avalonEditOptions = new TextEditorOptions(originalAvalonEditOptions);
this.originalSDOptions = originalSDOptions;
this.container = container;
// Update overridden options once
UpdateOverriddenProperties();
CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += OnFormattingPolicyUpdated;
this.originalAvalonEditOptions.PropertyChanged += OnOrigAvalonOptionsPropertyChanged;
this.originalSDOptions.PropertyChanged += OnSDOptionsPropertyChanged;
}
void OnFormattingPolicyUpdated(object sender, CSharpBinding.FormattingStrategy.CSharpFormattingPolicyUpdateEventArgs e)
{
// Update editor options from changed policy
UpdateOverriddenProperties();
OnPropertyChanged("IndentationSize");
OnPropertyChanged("IndentationString");
OnPropertyChanged("ConvertTabsToSpaces");
}
void UpdateOverriddenProperties()
{
avalonEditOptions.IndentationSize = container.GetEffectiveIndentationSize() ?? originalSDOptions.IndentationSize;
avalonEditOptions.ConvertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces() ?? originalSDOptions.ConvertTabsToSpaces;
}
void OnOrigAvalonOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if ((e.PropertyName != "IndentationSize") && (e.PropertyName != "IndentationString") && (e.PropertyName != "ConvertTabsToSpaces")) {
// Update values in our own TextEditorOptions instance
PropertyInfo propertyInfo = typeof(TextEditorOptions).GetProperty(e.PropertyName);
if (propertyInfo != null) {
propertyInfo.SetValue(avalonEditOptions, propertyInfo.GetValue(originalAvalonEditOptions));
}
} else {
UpdateOverriddenProperties();
}
OnPropertyChanged(e.PropertyName);
}
void OnSDOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
OnPropertyChanged(e.PropertyName);
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ICSharpCode.AvalonEdit.TextEditorOptions TextEditorOptions
{
get {
return avalonEditOptions;
}
}
#region Overridden properties
public int IndentationSize {
get {
// Get value from own TextEditorOptions instance
return avalonEditOptions.IndentationSize;
}
}
public string IndentationString {
get {
// Get value from own TextEditorOptions instance
return avalonEditOptions.IndentationString;
}
}
public bool ConvertTabsToSpaces {
get {
// Get value from own TextEditorOptions instance
return avalonEditOptions.ConvertTabsToSpaces;
}
}
#endregion
#region Rest of ITextEditorOptions implementation
public bool AutoInsertBlockEnd {
get {
return originalSDOptions.AutoInsertBlockEnd;
}
}
public int VerticalRulerColumn {
get {
return originalSDOptions.VerticalRulerColumn;
}
}
public bool UnderlineErrors {
get {
return originalSDOptions.UnderlineErrors;
}
}
public string FontFamily {
get {
return originalSDOptions.FontFamily;
}
}
public double FontSize {
get {
return originalSDOptions.FontSize;
}
}
#endregion
}
}

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs

@ -24,10 +24,8 @@ using ICSharpCode.Core; @@ -24,10 +24,8 @@ using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Completion;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Completion;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;

49
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionContext.cs

@ -17,17 +17,19 @@ @@ -17,17 +17,19 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop.Project;
using CSharpBinding.Parser;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Completion;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using CSharpBinding.Parser;
namespace CSharpBinding.Completion
{
@ -35,7 +37,7 @@ namespace CSharpBinding.Completion @@ -35,7 +37,7 @@ namespace CSharpBinding.Completion
{
public readonly ITextEditor Editor;
public readonly IDocument Document;
public readonly CSharpFullParseInformation ParseInformation;
public readonly IList<string> ConditionalSymbols;
public readonly ICompilation Compilation;
public readonly IProjectContent ProjectContent;
public readonly CSharpTypeResolveContext TypeResolveContextAtCaret;
@ -56,7 +58,7 @@ namespace CSharpBinding.Completion @@ -56,7 +58,7 @@ namespace CSharpBinding.Completion
if (projectContent == null)
return null;
return new CSharpCompletionContext(editor, parseInfo, compilation, projectContent, editor.Document, editor.Caret.Location);
return new CSharpCompletionContext(editor, parseInfo.SyntaxTree.ConditionalSymbols, compilation, projectContent, editor.Document, parseInfo.UnresolvedFile, editor.Caret.Location);
}
public static CSharpCompletionContext Get(ITextEditor editor, ITextSource fileContent, TextLocation currentLocation, FileName fileName)
@ -64,33 +66,50 @@ namespace CSharpBinding.Completion @@ -64,33 +66,50 @@ namespace CSharpBinding.Completion
IDocument document = new ReadOnlyDocument(fileContent);
// Don't require the very latest parse information, an older cached version is OK.
var parseInfo = SD.ParserService.Parse(fileName, document) as CSharpFullParseInformation;
var parseInfo = SD.ParserService.GetCachedParseInformation(fileName) as CSharpFullParseInformation;
if (parseInfo == null) {
parseInfo = SD.ParserService.Parse(fileName) as CSharpFullParseInformation;
}
if (parseInfo == null)
return null;
ICompilation compilation = SD.ParserService.GetCompilationForFile(fileName);
var projectContent = compilation.MainAssembly.UnresolvedAssembly as IProjectContent;
var project = SD.ProjectService.FindProjectContainingFile(fileName)as CSharpProject;
if (project == null)
return null;
var solutionSnapshot = SD.ParserService.GetCurrentSolutionSnapshot();
var projectContent = solutionSnapshot.GetProjectContent(project);
if (projectContent == null)
return null;
return new CSharpCompletionContext(editor, parseInfo, compilation, projectContent, document, currentLocation);
CSharpParser parser = new CSharpParser(project.CompilerSettings);
parser.GenerateTypeSystemMode = false;
SyntaxTree cu = parser.Parse(fileContent, Path.GetRandomFileName() + ".cs");
cu.Freeze();
CSharpUnresolvedFile unresolvedFile = cu.ToTypeSystem();
ICompilation compilation = projectContent.AddOrUpdateFiles(unresolvedFile).CreateCompilation(solutionSnapshot);
return new CSharpCompletionContext(editor, parseInfo.SyntaxTree.ConditionalSymbols, compilation, projectContent, document, unresolvedFile, currentLocation);
}
private CSharpCompletionContext(ITextEditor editor, CSharpFullParseInformation parseInfo, ICompilation compilation, IProjectContent projectContent, IDocument document, TextLocation caretLocation)
private CSharpCompletionContext(ITextEditor editor, IList<string> conditionalSymbols, ICompilation compilation, IProjectContent projectContent, IDocument document, CSharpUnresolvedFile unresolvedFile, TextLocation caretLocation)
{
Debug.Assert(editor != null);
Debug.Assert(parseInfo != null);
Debug.Assert(unresolvedFile != null);
Debug.Assert(compilation != null);
Debug.Assert(projectContent != null);
Debug.Assert(document != null);
this.Editor = editor;
this.Document = document;
this.ParseInformation = parseInfo;
this.ConditionalSymbols = conditionalSymbols;
this.Compilation = compilation;
this.ProjectContent = projectContent;
this.TypeResolveContextAtCaret = parseInfo.UnresolvedFile.GetTypeResolveContext(compilation, caretLocation);
this.CompletionContextProvider = new DefaultCompletionContextProvider(document, parseInfo.UnresolvedFile);
this.CompletionContextProvider.ConditionalSymbols.AddRange(parseInfo.SyntaxTree.ConditionalSymbols);
this.TypeResolveContextAtCaret = unresolvedFile.GetTypeResolveContext(compilation, caretLocation);
this.CompletionContextProvider = new DefaultCompletionContextProvider(document, unresolvedFile);
this.CompletionContextProvider.ConditionalSymbols.AddRange(conditionalSymbols);
}
}
}

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs

@ -148,7 +148,7 @@ namespace CSharpBinding.Completion @@ -148,7 +148,7 @@ namespace CSharpBinding.Completion
IEnumerable<ICompletionData> ICompletionDataFactory.CreatePreProcessorDefinesCompletionData()
{
return completionContext.ParseInformation.SyntaxTree.ConditionalSymbols.Select(def => new CompletionData(def));
return completionContext.ConditionalSymbols.Select(def => new CompletionData(def));
}
ICompletionData ICompletionDataFactory.CreateImportCompletionData(IType type, bool useFullName, bool addForTypeCreation)

3
src/AddIns/Debugger/Debugger.AddIn/Breakpoints/BreakpointEditorPopup.xaml.cs

@ -41,7 +41,8 @@ namespace Debugger.AddIn.Breakpoints @@ -41,7 +41,8 @@ namespace Debugger.AddIn.Breakpoints
{
InitializeComponent();
this.DataContext = target;
condition.DebugContext = new DebuggerCompletionContext(target.FileName, target.Location);
condition.ContextFileName = target.FileName;
condition.ContextTextLocation = target.Location;
condition.FontFamily = new FontFamily(SD.EditorControlService.GlobalOptions.FontFamily);
condition.FontSize = SD.EditorControlService.GlobalOptions.FontSize;
if (target.Condition == null)

18
src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs

@ -64,7 +64,8 @@ namespace Debugger.AddIn.Pads.Controls @@ -64,7 +64,8 @@ namespace Debugger.AddIn.Pads.Controls
set { SetValue(IsEditableProperty, value); }
}
public DebuggerCompletionContext DebugContext { get; set; }
public FileName ContextFileName { get; set; }
public TextLocation ContextTextLocation { get; set; }
static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
@ -127,20 +128,15 @@ namespace Debugger.AddIn.Pads.Controls @@ -127,20 +128,15 @@ namespace Debugger.AddIn.Pads.Controls
void editor_TextArea_TextEntered(object sender, TextCompositionEventArgs e)
{
if (e.Text == ".") {
DebuggerCompletionContext context = null;
StackFrame frame = WindowsDebugger.CurrentStackFrame;
if (frame == null) {
if (DebugContext != null) {
context = DebugContext;
}
} else {
context = new DebuggerCompletionContext(frame);
if (frame != null) {
ContextFileName = new FileName(frame.NextStatement.Filename);
ContextTextLocation = new TextLocation(frame.NextStatement.StartLine, frame.NextStatement.StartColumn);
}
if (context == null) return;
var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), context);
if (ContextFileName == null) return;
var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), ContextFileName, ContextTextLocation, SD.ParserService.ResolveContext(ContextFileName, ContextTextLocation));
if (binding == null) return;
binding.HandleKeyPressed(editorAdapter, '.');
SD.ParserService.ParseFileAsync(context.FileName).FireAndForget();
} else {
// TODO : implement automated error checking CSharpParser.ParseExpression does not report useful error messages.
// Error[] errors;

5
src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs

@ -86,10 +86,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -86,10 +86,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
void ShowDotCompletion(StackFrame frame, string currentText)
{
var binding = DebuggerDotCompletion.PrepareDotCompletion(currentText, new DebuggerCompletionContext(frame));
var fileName = new ICSharpCode.Core.FileName(frame.NextStatement.Filename);
var textLocation = new TextLocation(frame.NextStatement.StartLine, frame.NextStatement.StartColumn);
var binding = DebuggerDotCompletion.PrepareDotCompletion(currentText, fileName, textLocation, SD.ParserService.ResolveContext(fileName, textLocation));
if (binding == null) return;
binding.HandleKeyPressed(console.TextEditor, '.');
SD.ParserService.ParseFileAsync(new ICSharpCode.Core.FileName(frame.NextStatement.Filename)).FireAndForget();
}
protected override ToolBar BuildToolBar()

156
src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs

@ -41,162 +41,12 @@ namespace Debugger.AddIn.Pads.Controls @@ -41,162 +41,12 @@ namespace Debugger.AddIn.Pads.Controls
return !errors.Any();
}
public static ICodeCompletionBinding PrepareDotCompletion(string expressionToComplete, DebuggerCompletionContext context)
public static ICodeCompletionBinding PrepareDotCompletion(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context)
{
var lang = SD.LanguageService.GetLanguageByFileName(context.FileName);
var lang = SD.LanguageService.GetLanguageByFileName(fileName);
if (lang == null)
return null;
string content = GeneratePartialClassContextStub(context);
const string caretPoint = "$__Caret_Point__$;";
int caretOffset = content.IndexOf(caretPoint, StringComparison.Ordinal) + expressionToComplete.Length;
SD.Log.DebugFormatted("context used for dot completion: {0}", content.Replace(caretPoint, "$" + expressionToComplete + "|$"));
var doc = new ReadOnlyDocument(content.Replace(caretPoint, expressionToComplete));
return lang.CreateCompletionBinding(context.FileName, doc.GetLocation(caretOffset), doc.CreateSnapshot());
}
static string GeneratePartialClassContextStub(DebuggerCompletionContext context)
{
var compilation = SD.ParserService.GetCompilationForFile(context.FileName);
var file = SD.ParserService.GetExistingUnresolvedFile(context.FileName);
if (compilation == null || file == null)
return "";
var unresolvedMember = file.GetMember(context.Location);
if (unresolvedMember == null)
return "";
var member = unresolvedMember.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly));
if (member == null)
return "";
var builder = new TypeSystemAstBuilder();
MethodDeclaration decl;
if (unresolvedMember is IMethod) {
// If it's a method, convert it directly (including parameters + type parameters)
decl = (MethodDeclaration)builder.ConvertEntity(member);
} else {
// Otherwise, create a method anyways, and copy the parameters
decl = new MethodDeclaration();
if (member is IParameterizedMember) {
foreach (var p in ((IParameterizedMember)member).Parameters) {
decl.Parameters.Add(builder.ConvertParameter(p));
}
}
}
decl.Name = "__DebuggerStub__";
decl.ReturnType = builder.ConvertType(member.ReturnType);
decl.Modifiers = unresolvedMember.IsStatic ? Modifiers.Static : Modifiers.None;
// Make the method look like an explicit interface implementation so that it doesn't appear in CC
decl.PrivateImplementationType = new SimpleType("__DummyType__");
decl.Body = GenerateBodyFromContext(builder, context);
return WrapInType(unresolvedMember.DeclaringTypeDefinition, decl).ToString();
}
static BlockStatement GenerateBodyFromContext(TypeSystemAstBuilder builder, DebuggerCompletionContext context)
{
var body = new BlockStatement();
foreach (var v in context.Variables)
body.Statements.Add(new VariableDeclarationStatement(builder.ConvertType(v.Type), v.Name));
body.Statements.Add(new ExpressionStatement(new IdentifierExpression("$__Caret_Point__$")));
return body;
}
static AstNode WrapInType(IUnresolvedTypeDefinition entity, EntityDeclaration decl)
{
if (entity == null)
return decl;
// Wrap decl in TypeDeclaration
decl = new TypeDeclaration {
ClassType = GetClassType(entity),
Modifiers = Modifiers.Partial,
Name = entity.Name,
Members = { decl }
};
if (entity.DeclaringTypeDefinition != null) {
// Handle nested types
return WrapInType(entity.DeclaringTypeDefinition, decl);
}
if (string.IsNullOrEmpty(entity.Namespace))
return decl;
return new NamespaceDeclaration(entity.Namespace) {
Members = {
decl
}
};
}
static ClassType GetClassType(IUnresolvedTypeDefinition entity)
{
switch (entity.Kind) {
case TypeKind.Interface:
return ClassType.Interface;
case TypeKind.Struct:
return ClassType.Struct;
default:
return ClassType.Class;
}
}
}
public class LocalVariable
{
readonly IType type;
public IType Type {
get {
return type;
}
}
readonly string name;
public string Name {
get {
return name;
}
}
public LocalVariable(IType type, string name)
{
this.type = type;
this.name = name;
}
}
public class DebuggerCompletionContext
{
readonly FileName fileName;
TextLocation location;
readonly LocalVariable[] variables;
public DebuggerCompletionContext(StackFrame frame)
{
fileName = new FileName(frame.NextStatement.Filename);
location = new TextLocation(frame.NextStatement.StartLine, frame.NextStatement.StartColumn);
variables = frame.GetLocalVariables().Select(v => new LocalVariable(v.Type, v.Name)).ToArray();
}
public DebuggerCompletionContext(FileName fileName, TextLocation location)
{
this.fileName = fileName;
this.location = location;
this.variables = SD.ParserService.ResolveContext(fileName, location)
.LocalVariables.Select(v => new LocalVariable(v.Type, v.Name)).ToArray();
}
public FileName FileName {
get {
return fileName;
}
}
public TextLocation Location {
get {
return location;
}
}
public LocalVariable[] Variables {
get {
return variables;
}
return lang.CreateCompletionBinding(expressionToComplete, fileName, location, context);
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -633,6 +633,8 @@ namespace ICSharpCode.SharpDevelop.Services @@ -633,6 +633,8 @@ namespace ICSharpCode.SharpDevelop.Services
return;
if (CurrentStackFrame == null)
return;
if (!e.InDocument)
return;
var resolveResult = SD.ParserService.Resolve(e.Editor, e.LogicalPosition, CurrentStackFrame.AppDomain.Compilation);
if (resolveResult == null)
return;

3
src/AddIns/VersionControl/GitAddIn/Src/Git.cs

@ -94,7 +94,8 @@ namespace ICSharpCode.GitAddIn @@ -94,7 +94,8 @@ namespace ICSharpCode.GitAddIn
/// </summary>
public static string FindGit()
{
string[] paths = Environment.GetEnvironmentVariable("PATH").Split(';');
string pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
string[] paths = pathVariable.Split(new char[]{';'}, StringSplitOptions.RemoveEmptyEntries);
foreach (string path in paths) {
try {
string exe = Path.Combine(path, "git.exe");

8
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/UseOfMemberOfNullReference.cs

@ -34,10 +34,10 @@ using ICSharpCode.NRefactory.CSharp.Analysis; @@ -34,10 +34,10 @@ using ICSharpCode.NRefactory.CSharp.Analysis;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[IssueDescription("Use of (non-extension method) member of null value will cause a NullReferenceException",
Description = "Detects when a member of a null value is used",
Category = IssueCategories.CodeQualityIssues,
Severity = Severity.Warning)]
// [IssueDescription("Use of (non-extension method) member of null value will cause a NullReferenceException",
// Description = "Detects when a member of a null value is used",
// Category = IssueCategories.CodeQualityIssues,
// Severity = Severity.Warning)]
public class UseOfMemberOfNullReference : GatherVisitorCodeIssueProvider
{
static readonly ISet<NullValueStatus> ProblematicNullStates = new HashSet<NullValueStatus> {

3
src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeViewItem.cs

@ -118,7 +118,8 @@ namespace ICSharpCode.TreeView @@ -118,7 +118,8 @@ namespace ICSharpCode.TreeView
protected override void OnContextMenuOpening(ContextMenuEventArgs e)
{
Node.ShowContextMenu(e);
if (Node != null)
Node.ShowContextMenu(e);
}
#endregion

12
src/Main/Base/Project/Parser/ProjectContentContainer.cs

@ -463,9 +463,15 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -463,9 +463,15 @@ namespace ICSharpCode.SharpDevelop.Parser
foreach (var file in assemblyFiles) {
progressMonitor.CancellationToken.ThrowIfCancellationRequested();
if (File.Exists(file)) {
var pc = SD.AssemblyParserService.GetAssembly(file, false, progressMonitor.CancellationToken);
if (pc != null) {
newReferences.Add(pc);
try {
var pc = SD.AssemblyParserService.GetAssembly(file, false, progressMonitor.CancellationToken);
if (pc != null) {
newReferences.Add(pc);
}
} catch (IOException ex) {
LoggingService.Warn(ex);
} catch (BadImageFormatException ex) {
LoggingService.Warn(ex);
}
}
progressMonitor.Progress += (1.0 - assemblyResolvingProgress) / assemblyFiles.Count;

2
src/Main/Base/Project/Src/Project/AbstractProject.cs

@ -188,7 +188,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -188,7 +188,7 @@ namespace ICSharpCode.SharpDevelop.Project
try {
FileAttributes attributes = File.GetAttributes(FileName);
return ((FileAttributes.ReadOnly & attributes) == FileAttributes.ReadOnly);
} catch (FileNotFoundException) {
} catch (UnauthorizedAccessException) {
return false;
} catch (IOException) {
// directory not found, network path not available, etc.

2
src/Main/Base/Project/Src/Services/LanguageBinding/DefaultLanguageBinding.cs

@ -75,7 +75,7 @@ namespace ICSharpCode.SharpDevelop @@ -75,7 +75,7 @@ namespace ICSharpCode.SharpDevelop
}
}
public virtual ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ITextSource fileContent)
public virtual ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context)
{
throw new NotSupportedException();
}

5
src/Main/Base/Project/Src/Services/LanguageBinding/ILanguageBinding.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
@ -62,8 +63,8 @@ namespace ICSharpCode.SharpDevelop @@ -62,8 +63,8 @@ namespace ICSharpCode.SharpDevelop
}
/// <summary>
/// Creates a completion binding which works with a fileName and a location as context.
/// Creates a completion binding for a given expression and context.
/// </summary>
ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ITextSource fileContent);
ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context);
}
}

8
src/Main/SharpDevelop/Parser/ParserService.cs

@ -174,7 +174,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -174,7 +174,7 @@ namespace ICSharpCode.SharpDevelop.Parser
internal void RemoveEntry(ParserServiceEntry entry)
{
Debug.Assert(Monitor.IsEntered(entry));
Debug.Assert(entry.rwLock.IsWriteLockHeld);
lock (fileEntryDict) {
ParserServiceEntry entryAtKey;
if (fileEntryDict.TryGetValue(entry.fileName, out entryAtKey)) {
@ -190,7 +190,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -190,7 +190,7 @@ namespace ICSharpCode.SharpDevelop.Parser
internal void RegisterForCacheExpiry(ParserServiceEntry entry)
{
// This method should not be called within any locks
Debug.Assert(!Monitor.IsEntered(entry));
Debug.Assert(!(entry.rwLock.IsReadLockHeld || entry.rwLock.IsUpgradeableReadLockHeld || entry.rwLock.IsWriteLockHeld));
ParserServiceEntry expiredItem = null;
lock (cacheExpiryQueue) {
cacheExpiryQueue.Remove(entry); // remove entry from queue if it's already enqueued
@ -278,7 +278,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -278,7 +278,7 @@ namespace ICSharpCode.SharpDevelop.Parser
public ResolveResult Resolve(FileName fileName, TextLocation location, ITextSource fileContent, ICompilation compilation, CancellationToken cancellationToken)
{
var entry = GetFileEntry(fileName, true);
if (entry.parser == null)
if (entry.parser == null || location.IsEmpty)
return ErrorResolveResult.UnknownError;
IProject project = compilation != null ? compilation.GetProject() : null;
var parseInfo = entry.Parse(fileContent, project, cancellationToken);
@ -334,7 +334,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -334,7 +334,7 @@ namespace ICSharpCode.SharpDevelop.Parser
public Task<ResolveResult> ResolveAsync(FileName fileName, TextLocation location, ITextSource fileContent, ICompilation compilation, CancellationToken cancellationToken)
{
var entry = GetFileEntry(fileName, true);
if (entry.parser == null)
if (entry.parser == null || location.IsEmpty)
return Task.FromResult<ResolveResult>(ErrorResolveResult.UnknownError);
IProject project = compilation != null ? compilation.GetProject() : null;
return entry.ParseAsync(fileContent, project, cancellationToken).ContinueWith(

96
src/Main/SharpDevelop/Parser/ParserServiceEntry.cs

@ -54,6 +54,10 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -54,6 +54,10 @@ namespace ICSharpCode.SharpDevelop.Parser
List<ProjectEntry> entries = new List<ProjectEntry> { default(ProjectEntry) };
ITextSourceVersion currentVersion;
// Lock ordering: runningAsyncParseLock, rwLock, lock(parserService.fileEntryDict)
// (to avoid deadlocks, the locks may only be acquired in this order)
internal readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
public ParserServiceEntry(ParserService parserService, FileName fileName)
{
this.parserService = parserService;
@ -68,6 +72,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -68,6 +72,7 @@ namespace ICSharpCode.SharpDevelop.Parser
int FindIndexForProject(IProject parentProject)
{
Debug.Assert(rwLock.IsReadLockHeld || rwLock.IsUpgradeableReadLockHeld || rwLock.IsWriteLockHeld);
if (parentProject == null)
return 0;
for (int i = 0; i < entries.Count; i++) {
@ -81,7 +86,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -81,7 +86,8 @@ namespace ICSharpCode.SharpDevelop.Parser
public void AddOwnerProject(IProject project, bool isLinkedFile)
{
Debug.Assert(project != null);
lock (this) {
rwLock.EnterWriteLock();
try {
if (FindIndexForProject(project) >= 0)
throw new InvalidOperationException("The project alreadys owns the file");
ProjectEntry newEntry = new ProjectEntry(project, null, null);
@ -92,6 +98,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -92,6 +98,8 @@ namespace ICSharpCode.SharpDevelop.Parser
} else {
entries.Insert(0, newEntry);
}
} finally {
rwLock.ExitWriteLock();
}
}
@ -100,7 +108,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -100,7 +108,8 @@ namespace ICSharpCode.SharpDevelop.Parser
Debug.Assert(project != null);
ProjectEntry oldEntry;
bool removedLastOwner = false;
lock (this) {
rwLock.EnterWriteLock();
try {
int index = FindIndexForProject(project);
if (index < 0)
throw new InvalidOperationException("The project does not own the file");
@ -111,6 +120,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -111,6 +120,8 @@ namespace ICSharpCode.SharpDevelop.Parser
} else {
entries.RemoveAt(index);
}
} finally {
rwLock.ExitWriteLock();
}
if (oldEntry.UnresolvedFile != null) {
project.OnParseInformationUpdated(new ParseInformationEventArgs(project, oldEntry.UnresolvedFile, null));
@ -128,6 +139,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -128,6 +139,7 @@ namespace ICSharpCode.SharpDevelop.Parser
/// </summary>
int CompareVersions(ITextSourceVersion newVersion)
{
Debug.Assert(rwLock.IsReadLockHeld || rwLock.IsUpgradeableReadLockHeld || rwLock.IsWriteLockHeld);
if (currentVersion != null && newVersion != null && currentVersion.BelongsToSameDocumentAs(newVersion))
return currentVersion.CompareAge(newVersion);
else
@ -137,7 +149,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -137,7 +149,8 @@ namespace ICSharpCode.SharpDevelop.Parser
#region Expire Cache + GetExistingUnresolvedFile + GetCachedParseInformation
public void ExpireCache()
{
lock (this) {
rwLock.EnterWriteLock();
try {
if (PrimaryProject == null) {
parserService.RemoveEntry(this);
} else {
@ -148,12 +161,15 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -148,12 +161,15 @@ namespace ICSharpCode.SharpDevelop.Parser
}
// force re-parse on next ParseFile() call even if unchanged
this.currentVersion = null;
} finally {
rwLock.ExitWriteLock();
}
}
public IUnresolvedFile GetExistingUnresolvedFile(ITextSourceVersion version, IProject parentProject)
{
lock (this) {
rwLock.EnterReadLock();
try {
if (version != null && CompareVersions(version) != 0) {
return null;
}
@ -161,12 +177,15 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -161,12 +177,15 @@ namespace ICSharpCode.SharpDevelop.Parser
if (index < 0)
return null;
return entries[index].UnresolvedFile;
} finally {
rwLock.ExitReadLock();
}
}
public ParseInformation GetCachedParseInformation(ITextSourceVersion version, IProject parentProject)
{
lock (this) {
rwLock.EnterReadLock();
try {
if (version != null && CompareVersions(version) != 0) {
return null;
}
@ -174,6 +193,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -174,6 +193,8 @@ namespace ICSharpCode.SharpDevelop.Parser
if (index < 0)
return null;
return entries[index].CachedParseInformation;
} finally {
rwLock.ExitReadLock();
}
}
#endregion
@ -218,7 +239,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -218,7 +239,8 @@ namespace ICSharpCode.SharpDevelop.Parser
}
ProjectEntry result;
lock (this) {
rwLock.EnterUpgradeableReadLock();
try {
int index = FindIndexForProject(parentProject);
int versionComparison = CompareVersions(fileContent.Version);
if (versionComparison > 0 || index < 0) {
@ -253,24 +275,32 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -253,24 +275,32 @@ namespace ICSharpCode.SharpDevelop.Parser
}
// Only if all parse runs succeeded, register the parse information.
currentVersion = fileContent.Version;
for (int i = 0; i < entries.Count; i++) {
if (fullParseInformationRequested || (entries[i].CachedParseInformation != null && results[i].NewParseInformation.IsFullParseInformation))
entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, results[i].NewParseInformation);
else
entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, null);
if (entries[i].Project != null)
entries[i].Project.OnParseInformationUpdated(results[i]);
parserService.RaiseParseInformationUpdated(results[i]);
rwLock.EnterWriteLock();
try {
currentVersion = fileContent.Version;
for (int i = 0; i < entries.Count; i++) {
if (fullParseInformationRequested || (entries[i].CachedParseInformation != null && results[i].NewParseInformation.IsFullParseInformation))
entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, results[i].NewParseInformation);
else
entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, null);
if (entries[i].Project != null)
entries[i].Project.OnParseInformationUpdated(results[i]);
parserService.RaiseParseInformationUpdated(results[i]);
}
result = entries[index];
} finally {
rwLock.ExitWriteLock();
}
result = entries[index];
} // exit lock
} finally {
rwLock.ExitUpgradeableReadLock();
}
parserService.RegisterForCacheExpiry(this);
return result;
}
ParseInformation ParseWithExceptionHandling(ITextSource fileContent, bool fullParseInformationRequested, IProject project, CancellationToken cancellationToken)
{
Debug.Assert(rwLock.IsUpgradeableReadLockHeld && !rwLock.IsWriteLockHeld);
#if DEBUG
if (Debugger.IsAttached)
return parser.Parse(fileName, fileContent, fullParseInformationRequested, project, cancellationToken);
@ -285,6 +315,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -285,6 +315,8 @@ namespace ICSharpCode.SharpDevelop.Parser
#endregion
#region ParseAsync
/// <summary>lock object for protecting the runningAsyncParse* fields</summary>
object runningAsyncParseLock = new object();
Task<ProjectEntry> runningAsyncParseTask;
ITextSourceVersion runningAsyncParseFileContentVersion;
IProject runningAsyncParseProject;
@ -324,19 +356,24 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -324,19 +356,24 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
Task<ProjectEntry> task;
lock (this) {
lock (runningAsyncParseLock) {
if (fileContent != null) {
// Optimization:
// don't start a background task if fileContent was specified and up-to-date parse info is available
int index = FindIndexForProject(parentProject);
int versionComparison = CompareVersions(fileContent.Version);
if (versionComparison == 0 && index >= 0) {
// Ensure we have parse info for the specified project (entry.UnresolvedFile is null for newly registered projects)
// If full parse info is requested, ensure we have full parse info.
if (entries[index].UnresolvedFile != null && !(requestFullParseInformation && entries[index].CachedParseInformation == null)) {
// We already have the requested version parsed, just return it:
return Task.FromResult(entries[index]);
rwLock.EnterReadLock();
try {
int index = FindIndexForProject(parentProject);
int versionComparison = CompareVersions(fileContent.Version);
if (versionComparison == 0 && index >= 0) {
// Ensure we have parse info for the specified project (entry.UnresolvedFile is null for newly registered projects)
// If full parse info is requested, ensure we have full parse info.
if (entries[index].UnresolvedFile != null && !(requestFullParseInformation && entries[index].CachedParseInformation == null)) {
// We already have the requested version parsed, just return it:
return Task.FromResult(entries[index]);
}
}
} finally {
rwLock.ExitReadLock();
}
// Optimization:
// if an equivalent task is already running, return that one instead
@ -356,7 +393,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -356,7 +393,7 @@ namespace ICSharpCode.SharpDevelop.Parser
}
return DoParse(fileContent, parentProject, requestFullParseInformation, cancellationToken);
} finally {
lock (this) {
lock (runningAsyncParseLock) {
runningAsyncParseTask = null;
runningAsyncParseFileContentVersion = null;
runningAsyncParseProject = null;
@ -383,7 +420,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -383,7 +420,8 @@ namespace ICSharpCode.SharpDevelop.Parser
throw new ArgumentNullException("unresolvedFile");
FreezableHelper.Freeze(unresolvedFile);
var newParseInfo = new ParseInformation(unresolvedFile, null, false);
lock (this) {
rwLock.EnterWriteLock();
try {
int index = FindIndexForProject(project);
if (index >= 0) {
currentVersion = null;
@ -392,6 +430,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -392,6 +430,8 @@ namespace ICSharpCode.SharpDevelop.Parser
project.OnParseInformationUpdated(args);
parserService.RaiseParseInformationUpdated(args);
}
} finally {
rwLock.ExitWriteLock();
}
}
}

12
src/Tools/StressTest/StressTest.sln

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.3
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
# SharpDevelop 5.0
VisualStudioVersion = 12.0.20827.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StressTest", "StressTest\StressTest.csproj", "{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}"
EndProject
Global
@ -10,9 +12,9 @@ Global @@ -10,9 +12,9 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}.Debug|x86.Build.0 = Debug|x86
{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}.Debug|x86.ActiveCfg = Debug|x86
{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}.Release|x86.Build.0 = Release|x86
{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}.Debug|x86.Build.0 = Debug|x86
{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}.Release|x86.ActiveCfg = Release|x86
{30D10654-A5F5-4AC5-A370-E6DD4D0FAC50}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal

3
src/Tools/StressTest/StressTest/StressTest.csproj

@ -98,9 +98,6 @@ @@ -98,9 +98,6 @@
<ItemGroup>
<Page Include="UserControl.xaml" />
</ItemGroup>
<ItemGroup>
<Content Include="ProfilingSessions\Session20100225_205054.sdps" />
</ItemGroup>
<PropertyGroup>
<StartArguments>/addindir:"$(MsBuildProjectDirectory)\$(OutputPath)"</StartArguments>
</PropertyGroup>

1
src/Tools/StressTest/StressTest/UserControl.xaml.cs

@ -35,6 +35,7 @@ using ICSharpCode.Core; @@ -35,6 +35,7 @@ using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Workbench;
namespace StressTest
{

Loading…
Cancel
Save