Browse Source

Merge branch 'newNRILSpyDebugger' of github.com:icsharpcode/SharpDevelop

pull/80/head
Siegfried Pammer 12 years ago
parent
commit
4322d540f3
  1. 8
      SharpDevelop.sln
  2. 9
      src/AddIns/Analysis/Profiler/X64Converter/Program.cs
  3. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
  4. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpInsightItem.cs
  5. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/SegmentTrackingOutputFormatter.cs
  6. 2
      src/AddIns/BackendBindings/CppBinding/CppBinding/CppBinding.addin
  7. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin
  8. 9
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  9. 17
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs
  10. 62
      src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs
  11. 2
      src/AddIns/Debugger/Debugger.AddIn/Service/DebuggerCommands.cs
  12. 8
      src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs
  13. 24
      src/AddIns/Debugger/Debugger.Core/NDebugger.cs
  14. 14
      src/AddIns/Debugger/Debugger.Core/Process.cs
  15. 8
      src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs
  16. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/QuickClassBrowser.cs
  17. 92
      src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs
  18. 7
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin
  19. 10
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj
  20. 249
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDecompilerService.cs
  21. 29
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyFullParseInformation.cs
  22. 75
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyParser.cs
  23. 55
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs
  24. 64
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyUnresolvedFile.cs
  25. 107
      src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyAssemblyResolver.cs
  26. 4
      src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyController.cs
  27. 2
      src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/OpenInILSpyCommand.cs
  28. 8
      src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs
  29. 111
      src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs
  30. 2
      src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs
  31. 49
      src/Libraries/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs
  32. 4
      src/Libraries/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  33. 12
      src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  34. 2
      src/Libraries/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  35. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/UseStringFormatAction.cs
  36. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  37. 45
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
  38. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs
  39. 47
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
  40. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs
  41. 7
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
  42. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  43. 153
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs
  44. 629
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  45. 60
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/IOutputFormatter.cs
  46. 161
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/ITokenWriter.cs
  47. 122
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertMissingTokensDecorator.cs
  48. 184
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertRequiredSpacesDecorator.cs
  49. 157
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertSpecialsDecorator.cs
  50. 359
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/TextWriterOutputFormatter.cs
  51. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
  52. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpUnresolvedFile.cs
  53. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.ConsistencyCheck/Xml/XmlReaderTest.cs
  54. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs
  55. 87
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertMissingTokensDecoratorTests.cs
  56. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs
  57. 101
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ConsistencyChecker.cs
  58. 84
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseSelfTests.cs
  59. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  60. 21
      src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs
  61. 8
      src/Main/Base/Project/Dom/ClassBrowser/IClassBrowser.cs
  62. 5
      src/Main/Base/Project/Dom/ClassBrowser/MemberTreeNode.cs
  63. 18
      src/Main/Base/Project/Dom/ClassBrowser/WorkspaceModel.cs
  64. 13
      src/Main/Base/Project/Dom/ClassBrowser/WorkspaceTreeNode.cs
  65. 16
      src/Main/Base/Project/Dom/IAssemblyModel.cs
  66. 30
      src/Main/Base/Project/Dom/IEntityModelContext.cs
  67. 5
      src/Main/Base/Project/Dom/IMemberModel.cs
  68. 2
      src/Main/Base/Project/Dom/IModelFactory.cs
  69. 59
      src/Main/Base/Project/Dom/ModelFactoryExtensions.cs
  70. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  71. 58
      src/Main/Base/Project/Parser/DefaultAssemblySearcher.cs
  72. 34
      src/Main/Base/Project/Parser/IAssemblyParserService.cs
  73. 2
      src/Main/Base/Project/Parser/ProjectContentContainer.cs
  74. 15
      src/Main/Base/Project/Src/Project/CompilableProject.cs
  75. 33
      src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs
  76. 7
      src/Main/SharpDevelop/Dom/AssemblyModel.cs
  77. 15
      src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs
  78. 7
      src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs
  79. 2
      src/Main/SharpDevelop/Dom/ModelFactory.cs
  80. 118
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs
  81. 22
      src/Main/SharpDevelop/Parser/ParserDescriptor.cs
  82. 4
      src/Main/SharpDevelop/Parser/ParserDoozer.cs

8
SharpDevelop.sln

@ -251,6 +251,10 @@ Global @@ -251,6 +251,10 @@ Global
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}.Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Debug|Any CPU.ActiveCfg = net_4_5_Debug|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
{2FF700C2-A38A-48BD-A637-8CAFD4FE6237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2FF700C2-A38A-48BD-A637-8CAFD4FE6237}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2FF700C2-A38A-48BD-A637-8CAFD4FE6237}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -507,10 +511,6 @@ Global @@ -507,10 +511,6 @@ Global
{3DF4060F-5EE0-41CF-8096-F27355FD5511}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DF4060F-5EE0-41CF-8096-F27355FD5511}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF4060F-5EE0-41CF-8096-F27355FD5511}.Release|Any CPU.Build.0 = Release|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Debug|Any CPU.ActiveCfg = net_4_5_Debug|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Debug|Any CPU.Build.0 = net_4_5_Debug|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Release|Any CPU.ActiveCfg = net_4_5_Release|Any CPU
{2A705FC6-1A9E-4941-9E47-254D79F2D9D5}.Release|Any CPU.Build.0 = net_4_5_Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

9
src/AddIns/Analysis/Profiler/X64Converter/Program.cs

@ -25,6 +25,9 @@ namespace X64Converter @@ -25,6 +25,9 @@ namespace X64Converter
foreach (string path in map) {
CSharpParser parser = new CSharpParser();
#if DEBUG
parser.CompilerSettings.ConditionalSymbols.Add("DEBUG");
#endif
string filePath = path + ".cs";
if (File.Exists(filePath)) {
@ -67,6 +70,12 @@ namespace X64Converter @@ -67,6 +70,12 @@ namespace X64Converter
{
bool copyAllMembers;
public override object VisitNewLine(NewLineNode newLineNode)
{
newLineNode.Remove();
return base.VisitNewLine(newLineNode);
}
public override object VisitSimpleType(SimpleType simpleType)
{
simpleType.Identifier = simpleType.Identifier.Replace("32", "64");

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

@ -55,7 +55,7 @@ @@ -55,7 +55,7 @@
<Path name = "/SharpDevelop/Parser">
<Parser id = "C#"
supportedextensions = ".cs"
supportedfilenamepattern = "\.(cs)$"
projectfileextension = ".csproj"
class = "CSharpBinding.Parser.TParser"/>
</Path>

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

@ -64,7 +64,7 @@ namespace CSharpBinding.Completion @@ -64,7 +64,7 @@ namespace CSharpBinding.Completion
get { return null; }
}
sealed class ParameterHighlightingOutputFormatter : TextWriterOutputFormatter
sealed class ParameterHighlightingOutputFormatter : TextWriterTokenWriter
{
StringBuilder b;
int highlightedParameterIndex;

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

@ -15,7 +15,7 @@ namespace CSharpBinding.Completion @@ -15,7 +15,7 @@ namespace CSharpBinding.Completion
/// <summary>
/// Output formatter that creates a dictionary from AST nodes to segments in the output text.
/// </summary>
public class SegmentTrackingOutputFormatter : TextWriterOutputFormatter
public class SegmentTrackingOutputFormatter : TextWriterTokenWriter
{
Dictionary<AstNode, ISegment> segments = new Dictionary<AstNode, ISegment>();
Stack<int> startOffsets = new Stack<int>();

2
src/AddIns/BackendBindings/CppBinding/CppBinding/CppBinding.addin

@ -77,7 +77,7 @@ @@ -77,7 +77,7 @@
<!--
<Path name="/SharpDevelop/Parser">
<Parser id="C++"
supportedextensions=".cpp;.c;.hpp;.h"
supportedfilenamepattern="\.(cpp|c|hpp|h)$"
projectfileextension="vcxproj"
class="ICSharpCode.CppBinding.Parser.CppParser" />
</Path>

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin

@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
<Path name = "/SharpDevelop/Parser">
<Parser id = "XAML"
supportedextensions = ".xaml"
supportedfilenamepattern = "\.(xaml)$"
class = "ICSharpCode.XamlBinding.XamlParser"/>
</Path>

9
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -87,6 +87,15 @@ @@ -87,6 +87,15 @@
class = "Debugger.AddIn.AddWatchExpressionCommand"/>
</Path>
<Path name="/SharpDevelop/Pads/ClassBrowser/Toolbar">
<Condition name = "IsProcessRunning" isdebugging="False" action="Disable">
<ToolbarItem id = "DebugExecutable"
icon = "Icons.16x16.Debug.Assembly"
tooltip = "${res:MainWindow.Windows.Debug.DebugExecutable}"
class = "Debugger.AddIn.DebugExecutableMenuCommand"/>
</Condition>
</Path>
<Path name = "/SharpDevelop/Workbench/Pads">
<Pad id = "BreakPointsPad"
category = "Debugger"

17
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs

@ -331,16 +331,17 @@ namespace Debugger.AddIn @@ -331,16 +331,17 @@ namespace Debugger.AddIn
var val = Convert(result.Input);
if (result.Conversion.IsBoxingConversion)
return val;
else if (result.Conversion.IsIdentityConversion)
if (result.Conversion.IsIdentityConversion)
return val;
else if (result.Conversion.IsNumericConversion) {
if (result.Conversion.IsNumericConversion) {
var convVal = CSharpPrimitiveCast.Cast(ReflectionHelper.GetTypeCode(result.Type), val.PrimitiveValue, false);
return Eval.CreateValue(evalThread, convVal);
} else if (result.Conversion.IsUserDefined)
}
if (result.Conversion.IsUserDefined)
return InvokeMethod(null, result.Conversion.Method, val);
else if (result.Conversion.IsReferenceConversion && result.Conversion.IsImplicit)
if (result.Conversion.IsReferenceConversion && result.Conversion.IsImplicit)
return val;
throw new NotImplementedException();
throw new NotImplementedException(string.Format("conversion '{0}' not implemented!", result.Conversion));
}
Value Visit(LocalResolveResult result)
@ -424,11 +425,11 @@ namespace Debugger.AddIn @@ -424,11 +425,11 @@ namespace Debugger.AddIn
sb.Append("}");
return sb.ToString();
} else if (val.Type.IsKnownType(KnownTypeCode.Char)) {
return "'" + CSharpOutputVisitor.ConvertChar((char)val.PrimitiveValue) + "'";
return "'" + TextWriterTokenWriter.ConvertChar((char)val.PrimitiveValue) + "'";
} else if (val.Type.IsKnownType(KnownTypeCode.String)) {
return "\"" + CSharpOutputVisitor.ConvertString((string)val.PrimitiveValue) + "\"";
return "\"" + TextWriterTokenWriter.ConvertString((string)val.PrimitiveValue) + "\"";
} else if (val.Type.IsPrimitiveType()) {
return CSharpOutputVisitor.PrintPrimitiveValue(val.PrimitiveValue);
return TextWriterTokenWriter.PrintPrimitiveValue(val.PrimitiveValue);
} else {
return val.InvokeToString(evalThread);
}

62
src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs

@ -7,9 +7,11 @@ using Debugger; @@ -7,9 +7,11 @@ using Debugger;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using System.Linq;
using ICSharpCode.SharpDevelop.Parser;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
@ -183,12 +185,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -183,12 +185,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
static IAssemblyModel CreateAssemblyModel(Module module)
{
// references??
IEntityModelContext context = new AssemblyEntityModelContext(module.Assembly.UnresolvedAssembly);
IAssemblyModel model = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(context);
if (model is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)model).Update(EmptyList<IUnresolvedTypeDefinition>.Instance, module.Assembly.TopLevelTypeDefinitions.SelectMany(td => td.Parts).ToList());
}
IEntityModelContext context = new DebuggerProcessEntityModelContext(module.Process, module);
IUpdateableAssemblyModel model = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(context);
var types = module.Assembly.TopLevelTypeDefinitions.SelectMany(td => td.Parts).ToList();
model.AssemblyName = module.UnresolvedAssembly.AssemblyName;
model.Update(EmptyList<IUnresolvedTypeDefinition>.Instance, types);
model.References = module.GetReferences().Select(r => new DomAssemblyName(r)).ToArray();
return model;
}
}
@ -224,6 +226,49 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -224,6 +226,49 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
}
class DebuggerProcessEntityModelContext : IEntityModelContext
{
Debugger.Process process;
Debugger.Module currentModule;
public DebuggerProcessEntityModelContext(Process process, Module currentModule)
{
if (process == null)
throw new ArgumentNullException("process");
if (currentModule == null)
throw new ArgumentNullException("currentModule");
this.process = process;
this.currentModule = currentModule;
}
public ICompilation GetCompilation()
{
var mainModule = currentModule;
return new SimpleCompilation(mainModule.UnresolvedAssembly, process.Modules.Where(m => m != mainModule).Select(m => m.UnresolvedAssembly));
}
public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2)
{
return false;
}
public ICSharpCode.SharpDevelop.Project.IProject Project {
get { return null; }
}
public string AssemblyName {
get { return currentModule.UnresolvedAssembly.AssemblyName; }
}
public string Location {
get { return currentModule.FullPath; }
}
public bool IsValid {
get { return true; }
}
}
/// <summary>
/// AddModuleToWorkspaceCommand.
/// </summary>
@ -238,12 +283,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -238,12 +283,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
public override void Execute(object parameter)
{
var classBrowser = SD.GetService<IClassBrowser>();
var modelFactory = SD.GetService<IModelFactory>();
if ((classBrowser != null) && (modelFactory != null)) {
if (classBrowser != null) {
IAssemblyModel assemblyModel = (IAssemblyModel) parameter;
// Create a new copy of this assembly model
IAssemblyModel newAssemblyModel = modelFactory.SafelyCreateAssemblyModelFromFile(assemblyModel.Context.Location);
IAssemblyModel newAssemblyModel = SD.AssemblyParserService.GetAssemblyModelSafe(new ICSharpCode.Core.FileName(assemblyModel.Context.Location), true);
if (newAssemblyModel != null)
classBrowser.MainAssemblyList.Assemblies.Add(newAssemblyModel);
}

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

@ -115,7 +115,7 @@ namespace Debugger.AddIn @@ -115,7 +115,7 @@ namespace Debugger.AddIn
}
} else {
OpenFileDialog dialog = new OpenFileDialog() {
Filter = ".NET Executable (*.exe) | *.exe",
Filter = ".NET executable|*.exe",
RestoreDirectory = true,
DefaultExt = "exe"
};

8
src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs

@ -353,7 +353,9 @@ namespace Debugger @@ -353,7 +353,9 @@ namespace Debugger
EnterCallback("CreateAppDomain", pAppDomain);
pAppDomain.Attach();
process.appDomains.Add(new AppDomain(process, pAppDomain));
AppDomain appDomain = new AppDomain(process, pAppDomain);
process.appDomains.Add(appDomain);
process.OnAppDomainCreated(appDomain);
ExitCallback();
}
@ -476,7 +478,9 @@ namespace Debugger @@ -476,7 +478,9 @@ namespace Debugger
{
EnterCallback("ExitAppDomain", pAppDomain);
process.appDomains.Remove(process.GetAppDomain(pAppDomain));
AppDomain appDomain = process.GetAppDomain(pAppDomain);
process.appDomains.Remove(appDomain);
process.OnAppDomainDestroyed(appDomain);
ExitCallback();
}

24
src/AddIns/Debugger/Debugger.Core/NDebugger.cs

@ -184,7 +184,7 @@ namespace Debugger @@ -184,7 +184,7 @@ namespace Debugger
foreach (Process process in this.Processes) {
foreach(Module module in process.Modules) {
breakpoint.SetBreakpoint(module);
}
}
}
}
@ -251,7 +251,7 @@ namespace Debugger @@ -251,7 +251,7 @@ namespace Debugger
{
// Detach all processes.
foreach(Process process in this.Processes) {
if (process == null || process.HasExited)
if (process == null || process.HasExited)
continue;
process.Detach();
}
@ -266,9 +266,9 @@ namespace Debugger @@ -266,9 +266,9 @@ namespace Debugger
// this option overrides the others
return false;
}
if (systemStartOptions.Contains("/debug") ||
systemStartOptions.Contains("/crashdebug") ||
systemStartOptions.Contains("/debugport") ||
if (systemStartOptions.Contains("/debug") ||
systemStartOptions.Contains("/crashdebug") ||
systemStartOptions.Contains("/debugport") ||
systemStartOptions.Contains("/baudrate")) {
return true;
} else {
@ -287,7 +287,7 @@ namespace Debugger @@ -287,7 +287,7 @@ namespace Debugger
if (!isPaused)
process.Break();
// We need to be paused for this
// We need to be paused for this
foreach(Module module in process.Modules) {
module.LoadSymbolsFromDisk(this.Options.SymbolsSearchPaths);
module.ResetJustMyCode();
@ -346,6 +346,18 @@ namespace Debugger @@ -346,6 +346,18 @@ namespace Debugger
}
}
[Serializable]
public class AppDomainEventArgs: DebuggerEventArgs
{
public AppDomain AppDomain { get; private set; }
public AppDomainEventArgs(AppDomain appDomain)
{
this.Process = appDomain.Process;
this.AppDomain = appDomain;
}
}
[Serializable]
public class MessageEventArgs : EventArgs
{

14
src/AddIns/Debugger/Debugger.Core/Process.cs

@ -32,6 +32,8 @@ namespace Debugger @@ -32,6 +32,8 @@ namespace Debugger
public event EventHandler<MessageEventArgs> LogMessage;
public event EventHandler<ModuleEventArgs> ModuleLoaded;
public event EventHandler<ModuleEventArgs> ModuleUnloaded;
public event EventHandler<AppDomainEventArgs> AppDomainCreated;
public event EventHandler<AppDomainEventArgs> AppDomainDestroyed;
public event EventHandler<DebuggerPausedEventArgs> Paused;
public event EventHandler<DebuggerEventArgs> Resumed;
public event EventHandler<DebuggerEventArgs> Exited;
@ -608,5 +610,17 @@ namespace Debugger @@ -608,5 +610,17 @@ namespace Debugger
}
#endregion
internal void OnAppDomainCreated(AppDomain appDomain)
{
if (AppDomainCreated != null)
AppDomainCreated(this, new AppDomainEventArgs(appDomain));
}
internal void OnAppDomainDestroyed(AppDomain appDomain)
{
if (AppDomainDestroyed != null)
AppDomainDestroyed(this, new AppDomainEventArgs(appDomain));
}
}
}

8
src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs

@ -176,6 +176,14 @@ namespace Debugger @@ -176,6 +176,14 @@ namespace Debugger
return GetInfo(assembly).Module;
}
public static IEnumerable<string> GetReferences(this Module module)
{
ModuleMetadataInfo info;
if (!weakTable.TryGetValue(module.UnresolvedAssembly, out info))
throw new ArgumentException("The assembly was not from the debugger type system");
return info.CecilModule.AssemblyReferences.Select(r => r.FullName);
}
public static uint GetMetadataToken(this ITypeDefinition typeDefinition)
{
var info = GetInfo(typeDefinition.ParentAssembly);

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/QuickClassBrowser.cs

@ -255,7 +255,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -255,7 +255,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
foreach (var member in compoundClass.Members) {
if (member.IsSynthetic)
continue;
bool isInSamePart = string.Equals(member.UnresolvedMember.UnresolvedFile.FileName, selectedClass.UnresolvedFile.FileName, StringComparison.OrdinalIgnoreCase);
bool isInSamePart = string.Equals(member.Region.FileName, selectedClass.Region.FileName, StringComparison.OrdinalIgnoreCase);
memberItems.Add(new EntityItem(member, ambience) { IsInSamePart = isInSamePart });
}
memberItems.Sort();

92
src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs

@ -4,82 +4,58 @@ @@ -4,82 +4,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn
{
sealed class DebuggerTextOutput : ITextOutput
public sealed class DebugInfoTokenWriterDecorator : DecoratingTokenWriter
{
readonly ITextOutput output;
readonly Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public readonly Dictionary<string, MethodDebugSymbols> DebugSymbols = new Dictionary<string, MethodDebugSymbols>();
public readonly Dictionary<string, ICSharpCode.NRefactory.TextLocation> MemberLocations = new Dictionary<string, ICSharpCode.NRefactory.TextLocation>();
public DebuggerTextOutput(ITextOutput output)
public DebugInfoTokenWriterDecorator(TokenWriter writer)
: base(writer)
{
this.output = output;
}
public ICSharpCode.NRefactory.TextLocation Location {
get { return output.Location; }
}
public void Indent()
{
output.Indent();
}
public void Unindent()
{
output.Unindent();
}
public void Write(char ch)
public override void StartNode(AstNode node)
{
output.Write(ch);
}
public void Write(string text)
{
output.Write(text);
}
public void WriteLine()
{
output.WriteLine();
}
public void WriteDefinition(string text, object definition, bool isLocal)
{
if (definition is MemberReference) {
MemberLocations[XmlDocKeyProvider.GetKey((MemberReference)definition)] = Location;
base.StartNode(node);
if (node.Annotation<MethodDebugSymbols>() != null) {
symbolsStack.Push(node.Annotation<MethodDebugSymbols>());
}
output.WriteDefinition(text, definition, isLocal);
}
public void WriteReference(string text, object reference, bool isLocal)
{
output.WriteReference(text, reference, isLocal);
}
public void AddDebugSymbols(MethodDebugSymbols methodDebugSymbols)
{
var id = XmlDocKeyProvider.GetKey(methodDebugSymbols.CecilMethod);
methodDebugSymbols.SequencePoints = methodDebugSymbols.SequencePoints.OrderBy(s => s.ILOffset).ToList();
this.DebugSymbols.Add(id, methodDebugSymbols);
output.AddDebugSymbols(methodDebugSymbols);
}
public void MarkFoldStart(string collapsedText, bool defaultCollapsed)
{
output.MarkFoldStart(collapsedText, defaultCollapsed);
}
public void MarkFoldEnd()
public override void EndNode(AstNode node)
{
output.MarkFoldEnd();
base.EndNode(node);
if (node is EntityDeclaration && node.Annotation<MemberReference>() != null) {
MemberLocations[XmlDocKeyProvider.GetKey(node.Annotation<MemberReference>())] = node.StartLocation;
}
// code mappings
var ranges = node.Annotation<List<ILRange>>();
if (symbolsStack.Count > 0 && ranges != null && ranges.Count > 0) {
symbolsStack.Peek().SequencePoints.Add(
new SequencePoint() {
ILRanges = ILRange.OrderAndJoin(ranges).ToArray(),
StartLocation = node.StartLocation,
EndLocation = node.EndLocation
});
}
if (node.Annotation<MethodDebugSymbols>() != null) {
var symbols = symbolsStack.Pop();
symbols.SequencePoints = symbols.SequencePoints.OrderBy(s => s.ILOffset).ToList();
symbols.StartLocation = node.StartLocation;
symbols.EndLocation = node.EndLocation;
DebugSymbols[XmlDocKeyProvider.GetKey(symbols.CecilMethod)] = symbols;
}
}
}
}

7
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin

@ -20,6 +20,13 @@ @@ -20,6 +20,13 @@
<Class id="ILSpy" class="ICSharpCode.ILSpyAddIn.NavigateToDecompiledEntityService"/>
</Path>
<Path name = "/SharpDevelop/Parser">
<Parser id = "ILSpy"
insertbefore="C#"
supportedfilenamepattern="^ilspy\://"
class = "ICSharpCode.ILSpyAddIn.ILSpyParser" />
</Path>
<!-- Text editor context menu: Launch ILSpy command -->
<Path name="/SharpDevelop/EntityContextMenu">
<MenuItem id="ILSpySeparator" type="Separator" />

10
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj

@ -66,8 +66,11 @@ @@ -66,8 +66,11 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="DebuggerTextOutput.cs" />
<Compile Include="ILSpyDecompilerService.cs" />
<Compile Include="ILSpyFullParseInformation.cs" />
<Compile Include="ILSpyParser.cs" />
<Compile Include="ILSpySymbolSource.cs" />
<Compile Include="LaunchILSpy\ILSpyAssemblyResolver.cs" />
<Compile Include="ILSpyUnresolvedFile.cs" />
<Compile Include="NavigateToDecompiledEntityService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="LaunchILSpy\ILSpyController.cs" />
@ -101,6 +104,11 @@ @@ -101,6 +104,11 @@
<Name>Mono.Cecil</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory.Cecil\ICSharpCode.NRefactory.Cecil.csproj">
<Project>{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}</Project>
<Name>ICSharpCode.NRefactory.Cecil</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>

249
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDecompilerService.cs

@ -0,0 +1,249 @@ @@ -0,0 +1,249 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn
{
/// <summary>
/// Description of DecompilerService.
/// </summary>
public static class ILSpyDecompilerService
{
class ModuleCacheInfo
{
public readonly DateTime LastUpdateTime;
public readonly WeakReference<ModuleDefinition> Module;
public ModuleCacheInfo(DateTime lastUpdateTime, ModuleDefinition assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
this.LastUpdateTime = lastUpdateTime;
this.Module = new WeakReference<ModuleDefinition>(assembly);
}
}
static readonly Dictionary<FileName, ModuleCacheInfo> moduleCache = new Dictionary<FileName, ModuleCacheInfo>();
static ModuleDefinition GetModuleDefinitionFromCache(FileName file)
{
if (file == null) return null;
ReaderParameters parameters = new ReaderParameters();
var resolver = new ILSpyAssemblyResolver(file);
var lastUpdateTime = File.GetLastWriteTimeUtc(file);
lock (moduleCache) {
ModuleCacheInfo info;
ModuleDefinition module;
if (!moduleCache.TryGetValue(file, out info)) {
module = ModuleDefinition.ReadModule(file, parameters);
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module));
return module;
} else if (info.LastUpdateTime < lastUpdateTime) {
moduleCache.Remove(file);
module = ModuleDefinition.ReadModule(file, parameters);
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module));
return module;
} else {
if (info.Module.TryGetTarget(out module))
return module;
module = ModuleDefinition.ReadModule(file, parameters);
info.Module.SetTarget(module);
return module;
}
}
}
class ILSpyAssemblyResolver : DefaultAssemblySearcher, IAssemblyResolver
{
public ISet<AssemblyDefinition> ResolvedAssemblies {
get { return resolvedAssemblies; }
}
public ILSpyAssemblyResolver(FileName fileName)
: base(fileName)
{
}
/// <summary>
/// Used to remember the referenced assemblies for the WeakReference cache policy.
/// </summary>
readonly ISet<AssemblyDefinition> resolvedAssemblies = new HashSet<AssemblyDefinition>();
AssemblyDefinition Resolve(DomAssemblyName name, ReaderParameters parameters)
{
var moduleDefinition = GetModuleDefinitionFromCache(FindAssembly(name));
if (moduleDefinition != null) {
resolvedAssemblies.Add(moduleDefinition.Assembly);
return moduleDefinition.Assembly;
}
return null;
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return Resolve(name, new ReaderParameters());
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
return Resolve(new DomAssemblyName(name.FullName), parameters);
}
public AssemblyDefinition Resolve(string fullName)
{
return Resolve(fullName, new ReaderParameters());
}
public AssemblyDefinition Resolve(string fullName, ReaderParameters parameters)
{
return Resolve(new DomAssemblyName(fullName), parameters);
}
}
public static ILSpyFullParseInformation DecompileType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
if (name == null)
throw new ArgumentNullException("name");
var astBuilder = CreateAstBuilder(name, cancellationToken);
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree);
}
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions
// can be garbage-collected once the code is decompiled.
var resolver = new ILSpyAssemblyResolver(name.AssemblyFile);
readerParameters.AssemblyResolver = resolver;
ModuleDefinition module = GetModuleDefinitionFromCache(name.AssemblyFile);
if (module == null)
throw new InvalidOperationException("Could not find assembly file");
TypeDefinition typeDefinition = module.GetType(name.Type.ReflectionName);
if (typeDefinition == null)
throw new InvalidOperationException("Could not find type");
DecompilerContext context = new DecompilerContext(module);
context.CancellationToken = cancellationToken;
AstBuilder astBuilder = new AstBuilder(context);
astBuilder.AddType(typeDefinition);
return astBuilder;
}
static ILSpyUnresolvedFile DoDecompile(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, cancellationToken));
}
}
public class DecompiledTypeReference : IEquatable<DecompiledTypeReference>
{
public FileName AssemblyFile { get; private set; }
public TopLevelTypeName Type { get; private set; }
public DecompiledTypeReference(FileName assemblyFile, TopLevelTypeName type)
{
this.AssemblyFile = assemblyFile;
this.Type = type;
}
public FileName ToFileName()
{
return FileName.Create("ilspy://" + AssemblyFile + "/" + EscapeTypeName(Type.ReflectionName) + ".cs");
}
static readonly Regex nameRegex = new Regex(@"^ilspy\://(.+)/(.+)\.cs$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static DecompiledTypeReference FromFileName(string filename)
{
var match = nameRegex.Match(filename);
if (!match.Success) return null;
string asm, typeName;
asm = match.Groups[1].Value;
typeName = UnescapeTypeName(match.Groups[2].Value);
return new DecompiledTypeReference(new FileName(asm), new TopLevelTypeName(typeName));
}
public static DecompiledTypeReference FromTypeDefinition(ITypeDefinition definition)
{
FileName assemblyLocation = definition.ParentAssembly.GetRuntimeAssemblyLocation();
if (assemblyLocation != null && SD.FileSystem.FileExists(assemblyLocation)) {
return new DecompiledTypeReference(assemblyLocation, definition.FullTypeName.TopLevelTypeName);
}
return null;
}
public static string EscapeTypeName(string typeName)
{
if (typeName == null)
throw new ArgumentNullException("typeName");
foreach (var ch in new[] { '_' }.Concat(Path.GetInvalidFileNameChars())) {
typeName = typeName.Replace(ch.ToString(), string.Format("_{0:X4}", (int)ch));
}
return typeName;
}
static readonly Regex unescapeRegex = new Regex(@"_([0-9A-F]{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static string UnescapeTypeName(string typeName)
{
if (typeName == null)
throw new ArgumentNullException("typeName");
typeName = unescapeRegex.Replace(typeName, m => ((char)int.Parse(m.Groups[1].Value, System.Globalization.NumberStyles.HexNumber)).ToString());
return typeName;
}
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
DecompiledTypeReference other = (DecompiledTypeReference)obj;
if (other == null)
return false;
return Equals(other);
}
public bool Equals(DecompiledTypeReference other)
{
return object.Equals(this.AssemblyFile, other.AssemblyFile) && this.Type == other.Type;
}
public override int GetHashCode()
{
int hashCode = 0;
unchecked {
if (AssemblyFile != null)
hashCode += 1000000007 * AssemblyFile.GetHashCode();
hashCode += 1000000009 * Type.GetHashCode();
}
return hashCode;
}
public static bool operator ==(DecompiledTypeReference lhs, DecompiledTypeReference rhs) {
if (ReferenceEquals(lhs, rhs))
return true;
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
return false;
return lhs.Equals(rhs);
}
public static bool operator !=(DecompiledTypeReference lhs, DecompiledTypeReference rhs) {
return !(lhs == rhs);
}
#endregion
}
}

29
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyFullParseInformation.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop.Parser;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn
{
/// <summary>
/// Description of ILSpyFullParseInformation.
/// </summary>
public class ILSpyFullParseInformation : ParseInformation
{
SyntaxTree syntaxTree;
public ILSpyFullParseInformation(ILSpyUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, SyntaxTree syntaxTree)
: base(unresolvedFile, parsedVersion, true)
{
this.syntaxTree = syntaxTree;
}
public SyntaxTree SyntaxTree { get { return syntaxTree; } }
}
}

75
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyParser.cs

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using ICSharpCode.SharpDevelop.Editor.Search;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.ILSpyAddIn
{
/// <summary>
/// This class "parses" a decompiled type to provide the information required
/// by the ParserService.
/// </summary>
public class ILSpyParser : IParser
{
public bool CanParse(string fileName)
{
return fileName != null && fileName.StartsWith("ilspy://", StringComparison.OrdinalIgnoreCase);
}
public ParseInformation Parse(FileName fileName, ITextSource fileContent, bool fullParseInformationRequested, IProject parentProject, CancellationToken cancellationToken)
{
return ILSpyDecompilerService.DecompileType(DecompiledTypeReference.FromFileName(fileName), cancellationToken);
}
public ResolveResult Resolve(ParseInformation parseInfo, TextLocation location, ICompilation compilation, CancellationToken cancellationToken)
{
var decompiledParseInfo = parseInfo as ILSpyFullParseInformation;
if (decompiledParseInfo == null)
throw new ArgumentException("Parse info does not have SyntaxTree");
return ResolveAtLocation.Resolve(compilation, null, decompiledParseInfo.SyntaxTree, location, cancellationToken);
}
public ResolveResult ResolveSnippet(ParseInformation parseInfo, TextLocation location, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void FindLocalReferences(ParseInformation parseInfo, ITextSource fileContent, IVariable variable, ICompilation compilation, Action<SearchResultMatch> callback, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public ICompilation CreateCompilationForSingleFile(FileName fileName, IUnresolvedFile unresolvedFile)
{
DecompiledTypeReference reference = DecompiledTypeReference.FromFileName(fileName);
if (reference != null) {
var model = SD.GetService<IClassBrowser>().FindAssemblyModel(reference.AssemblyFile);
if (model == null)
model = SD.AssemblyParserService.GetAssemblyModelSafe(reference.AssemblyFile, true);
if (model != null)
return model.Context.GetCompilation();
}
return new CSharpProjectContent()
.AddOrUpdateFiles(unresolvedFile)
.CreateCompilation();
}
public IReadOnlyList<string> TaskListTokens { get; set; }
}
}

55
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Debugger;
using ICSharpCode.Core;
@ -9,6 +8,7 @@ using ICSharpCode.Decompiler; @@ -9,6 +8,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.ILSpyAddIn
{
@ -21,28 +21,29 @@ namespace ICSharpCode.ILSpyAddIn @@ -21,28 +21,29 @@ namespace ICSharpCode.ILSpyAddIn
public bool IsCompilerGenerated(IMethod method)
{
var symbols = GetSymbols(method);
return symbols == null || symbols.SequencePoints.Count == 0;
return false;
}
public static MethodDebugSymbols GetSymbols(IMethod method)
{
// Use the non-specialised method definition to look up decompiled symbols
var typeName = DecompiledTypeReference.FromTypeDefinition(method.DeclaringTypeDefinition);
var id = IdStringProvider.GetIdString(method.MemberDefinition);
var content = DecompiledViewContent.Get(method);
if (content != null && content.DebugSymbols.ContainsKey(id)) {
return content.DebugSymbols[id];
if (typeName == null) return null;
var file = SD.ParserService.ParseFile(typeName.ToFileName()) as ILSpyUnresolvedFile;
if (file != null && file.DebugSymbols.ContainsKey(id)) {
return file.DebugSymbols[id];
}
return null;
}
public Debugger.SequencePoint GetSequencePoint(IMethod method, int iloffset)
{
var symbols = GetSymbols(method);
if (symbols == null)
return null;
string id = IdStringProvider.GetIdString(method.MemberDefinition);
var content = DecompiledViewContent.Get(method);
if (content == null || !content.DebugSymbols.ContainsKey(id))
return null;
var symbols = content.DebugSymbols[id];
var seqs = symbols.SequencePoints;
var seq = seqs.FirstOrDefault(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To));
if (seq == null)
@ -51,19 +52,21 @@ namespace ICSharpCode.ILSpyAddIn @@ -51,19 +52,21 @@ namespace ICSharpCode.ILSpyAddIn
// Use the widest sequence point containing the IL offset
iloffset = seq.ILOffset;
seq = seqs.Where(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To))
.OrderByDescending(p => p.ILRanges.Last().To - p.ILRanges.First().From)
.FirstOrDefault();
return seq.ToDebugger(symbols, content.VirtualFileName);
.OrderByDescending(p => p.ILRanges.Last().To - p.ILRanges.First().From)
.FirstOrDefault();
return seq.ToDebugger(symbols, content.PrimaryFileName);
}
return null;
}
public IEnumerable<Debugger.SequencePoint> GetSequencePoints(Module module, string filename, int line, int column)
{
var content = DecompiledViewContent.Get(new FileName(filename));
if (content == null)
var name = DecompiledTypeReference.FromFileName(filename);
if (name == null || !FileUtility.IsEqualFileName(module.FullPath, name.AssemblyFile))
yield break;
if (!FileUtility.IsEqualFileName(module.FullPath, content.AssemblyFile))
var content = DecompiledViewContent.Get(name);
if (content == null)
yield break;
TextLocation loc = new TextLocation(line, column);
@ -74,7 +77,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -74,7 +77,7 @@ namespace ICSharpCode.ILSpyAddIn
if (seq == null)
seq = symbols.SequencePoints.FirstOrDefault(p => line <= p.StartLocation.Line);
if (seq != null)
yield return seq.ToDebugger(symbols, content.VirtualFileName);
yield return seq.ToDebugger(symbols, content.PrimaryFileName);
}
}
@ -95,13 +98,17 @@ namespace ICSharpCode.ILSpyAddIn @@ -95,13 +98,17 @@ namespace ICSharpCode.ILSpyAddIn
if (symbols == null)
return null;
return symbols.LocalVariables.Select(v => new Debugger.ILLocalVariable() {
var context = new SimpleTypeResolveContext(method);
var loader = new CecilLoader();
return symbols.LocalVariables.Select(
v => new Debugger.ILLocalVariable() {
Index = v.OriginalVariable.Index,
Type = method.Compilation.FindType(KnownTypeCode.Object), // TODO
Name = v.Name,
IsCompilerGenerated = false,
ILRanges = new [] { new Debugger.ILRange(0, int.MaxValue) }
});
Type = loader.ReadTypeReference(v.Type).Resolve(context),
Name = v.Name,
IsCompilerGenerated = false,
ILRanges = new [] { new ILRange(0, int.MaxValue) }
});
}
}

64
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyUnresolvedFile.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.ILSpyAddIn
{
/// <summary>
/// Description of ILSpyUnresolvedFile.
/// </summary>
public class ILSpyUnresolvedFile : CSharpUnresolvedFile
{
DecompiledTypeReference name;
string output;
public static ILSpyUnresolvedFile Create(DecompiledTypeReference name, AstBuilder builder)
{
var writer = new StringWriter();
var target = new TextWriterTokenWriter(writer) { IndentationString = "\t" };
var output = new DebugInfoTokenWriterDecorator(TokenWriter.WrapInWriterThatSetsLocationsInAST(target));
builder.RunTransformations();
var syntaxTree = builder.SyntaxTree;
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(output, FormattingOptionsFactory.CreateSharpDevelop()));
ILSpyUnresolvedFile file = new ILSpyUnresolvedFile(name);
var v = new TypeSystemConvertVisitor(file);
syntaxTree.AcceptVisitor(v);
file.MemberLocations = output.MemberLocations;
file.DebugSymbols = output.DebugSymbols;
file.output = writer.ToString();
return file;
}
ILSpyUnresolvedFile(DecompiledTypeReference name)
{
this.name = name;
FileName = name.ToFileName();
}
public Dictionary<string, TextLocation> MemberLocations { get; private set; }
public Dictionary<string, MethodDebugSymbols> DebugSymbols { get; private set; }
public string Output {
get { return output; }
}
public FileName AssemblyFile {
get { return name.AssemblyFile; }
}
}
}

107
src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyAssemblyResolver.cs

@ -1,107 +0,0 @@ @@ -1,107 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Parser;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn.LaunchILSpy
{
class ILSpyAssemblyResolver : IAssemblyResolver
{
readonly DirectoryInfo directoryInfo;
readonly IDictionary<string, AssemblyDefinition> cache;
readonly IDictionary<string, AssemblyDefinition> localAssembliesCache;
public ILSpyAssemblyResolver(string decompiledAssemblyFolder)
{
if (string.IsNullOrEmpty(decompiledAssemblyFolder))
throw new ArgumentException("Invalid working folder");
FolderPath = decompiledAssemblyFolder;
this.directoryInfo = new DirectoryInfo(decompiledAssemblyFolder);
this.cache = new Dictionary<string, AssemblyDefinition> ();
this.localAssembliesCache = new Dictionary<string, AssemblyDefinition>();
ReadLocalAssemblies();
}
public string FolderPath {
get; private set;
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return this.Resolve(name, new ReaderParameters());
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (name == null)
throw new ArgumentNullException("name");
if (parameters == null)
throw new ArgumentNullException("parameters");
try {
AssemblyDefinition assembly = null;
if (cache.TryGetValue(name.FullName, out assembly))
return assembly;
// search into assemblyDecompiledFolder
if (localAssembliesCache.ContainsKey(name.FullName)) {
assembly = localAssembliesCache[name.FullName];
}
if (assembly == null) {
// search using ILSpy's GacInterop.FindAssemblyInNetGac()
string fileInGac = SD.GlobalAssemblyCache.FindAssemblyInNetGac(new DomAssemblyName(name.FullName));
if (!string.IsNullOrEmpty(fileInGac)) {
assembly = AssemblyDefinition.ReadAssembly(fileInGac, parameters);
}
}
// update caches
if (assembly != null) {
this.cache.Add(assembly.FullName, assembly);
}
return assembly;
} catch (Exception ex) {
LoggingService.Error("Exception (ILSpyAssemblyResolver): " + ex.Message);
return null;
}
}
public AssemblyDefinition Resolve(string fullName)
{
return this.Resolve(fullName, new ReaderParameters());
}
public AssemblyDefinition Resolve(string fullName, ReaderParameters parameters)
{
if (string.IsNullOrEmpty(fullName))
throw new ArgumentException("fullName is null or empty");
return Resolve(AssemblyNameReference.Parse(fullName), parameters);
}
void ReadLocalAssemblies()
{
// read local assemblies
foreach (var file in this.directoryInfo.GetFiles()) {
try {
var localAssembly = AssemblyDefinition.ReadAssembly(file.FullName);
localAssembliesCache.Add(localAssembly.FullName, localAssembly);
} catch {
// unable to read assembly file
}
}
}
}
}

4
src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyController.cs

@ -2,17 +2,13 @@ @@ -2,17 +2,13 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.ILSpyAddIn
{

2
src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/OpenInILSpyCommand.cs

@ -2,9 +2,7 @@ @@ -2,9 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.SharpDevelop.Editor.Bookmarks;
using ICSharpCode.SharpDevelop.Editor.Commands;
namespace ICSharpCode.ILSpyAddIn

8
src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs

@ -44,14 +44,18 @@ namespace ICSharpCode.ILSpyAddIn @@ -44,14 +44,18 @@ namespace ICSharpCode.ILSpyAddIn
if (string.IsNullOrEmpty(typeName))
throw new ArgumentException("typeName is null or empty");
var type = new TopLevelTypeName(typeName);
var target = new DecompiledTypeReference(assemblyFile, type);
foreach (var viewContent in SD.Workbench.ViewContentCollection.OfType<DecompiledViewContent>()) {
if (viewContent.AssemblyFile == assemblyFile && typeName == viewContent.FullTypeName) {
var viewContentName = viewContent.DecompiledTypeName;
if (viewContentName.AssemblyFile == assemblyFile && type == viewContentName.Type) {
viewContent.WorkbenchWindow.SelectWindow();
viewContent.JumpToEntity(entityIdString);
return;
}
}
SD.Workbench.ShowView(new DecompiledViewContent(assemblyFile, typeName, entityIdString));
SD.Workbench.ShowView(new DecompiledViewContent(target, entityIdString));
}
}
}

111
src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs

@ -12,18 +12,12 @@ using ICSharpCode.AvalonEdit.AddIn; @@ -12,18 +12,12 @@ using ICSharpCode.AvalonEdit.AddIn;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.ILSpyAddIn.LaunchILSpy;
using ICSharpCode.ILSpyAddIn;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor.Bookmarks;
using ICSharpCode.SharpDevelop.Workbench;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn
{
@ -32,14 +26,6 @@ namespace ICSharpCode.ILSpyAddIn @@ -32,14 +26,6 @@ namespace ICSharpCode.ILSpyAddIn
/// </summary>
class DecompiledViewContent : AbstractViewContentWithoutFile
{
readonly FileName assemblyFile;
readonly string fullTypeName;
public FileName VirtualFileName { get; private set; }
public override FileName PrimaryFileName {
get { return this.VirtualFileName; }
}
/// <summary>
/// Entity to jump to once decompilation has finished.
/// </summary>
@ -54,38 +40,29 @@ namespace ICSharpCode.ILSpyAddIn @@ -54,38 +40,29 @@ namespace ICSharpCode.ILSpyAddIn
public Dictionary<string, MethodDebugSymbols> DebugSymbols { get; private set; }
#region Constructor
public DecompiledViewContent(FileName assemblyFile, string fullTypeName, string entityTag)
public DecompiledViewContent(DecompiledTypeReference typeName, string entityTag)
{
this.VirtualFileName = FileName.Create("ilspy://" + assemblyFile + "/" + fullTypeName + ".cs");
this.DecompiledTypeName = typeName;
this.Services = codeEditor.GetRequiredService<IServiceContainer>();
this.assemblyFile = assemblyFile;
this.fullTypeName = fullTypeName;
this.jumpToEntityIdStringWhenDecompilationFinished = entityTag;
this.TitleName = "[" + ReflectionHelper.SplitTypeParameterCountFromReflectionName(typeName.Type.Name) + "]";
string shortTypeName = fullTypeName.Substring(fullTypeName.LastIndexOf('.') + 1);
this.TitleName = "[" + ReflectionHelper.SplitTypeParameterCountFromReflectionName(shortTypeName) + "]";
DecompilationThread();
// Thread thread = new Thread(DecompilationThread);
// thread.Name = "Decompiler (" + shortTypeName + ")";
// thread.Start();
// thread.Join();
InitializeView();
SD.BookmarkManager.BookmarkRemoved += BookmarkManager_Removed;
SD.BookmarkManager.BookmarkAdded += BookmarkManager_Added;
this.codeEditor.FileName = this.VirtualFileName;
this.codeEditor.FileName = this.DecompiledTypeName.ToFileName();
this.codeEditor.ActiveTextEditor.IsReadOnly = true;
this.codeEditor.ActiveTextEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
}
#endregion
public static DecompiledViewContent Get(FileName virtualFileName)
public static DecompiledViewContent Get(DecompiledTypeReference name)
{
var viewContents = SD.Workbench.ViewContentCollection.OfType<DecompiledViewContent>();
return viewContents.FirstOrDefault(c => c.VirtualFileName == virtualFileName);
return viewContents.FirstOrDefault(c => c.DecompiledTypeName == name);
}
public static DecompiledViewContent Get(IEntity entity)
@ -118,27 +95,25 @@ namespace ICSharpCode.ILSpyAddIn @@ -118,27 +95,25 @@ namespace ICSharpCode.ILSpyAddIn
if (string.IsNullOrEmpty(typeName))
throw new ArgumentException("typeName is null or empty");
var type = new FullTypeName(typeName);
foreach (var viewContent in SD.Workbench.ViewContentCollection.OfType<DecompiledViewContent>()) {
if (viewContent.AssemblyFile == assemblyFile && typeName == viewContent.FullTypeName) {
var viewContentName = viewContent.DecompiledTypeName;
if (viewContentName.AssemblyFile == assemblyFile && type == viewContentName.Type) {
return viewContent;
}
}
var newViewContent = new DecompiledViewContent(assemblyFile, typeName, null);
var newViewContent = new DecompiledViewContent(new DecompiledTypeReference(assemblyFile, new TopLevelTypeName(typeName)), null);
SD.Workbench.ShowView(newViewContent);
return newViewContent;
}
#region Properties
public FileName AssemblyFile {
get { return assemblyFile; }
}
public DecompiledTypeReference DecompiledTypeName { get; private set; }
/// <summary>
/// The reflection name of the top-level type displayed in this view content.
/// </summary>
public string FullTypeName {
get { return fullTypeName; }
public override FileName PrimaryFileName {
get { return this.DecompiledTypeName.ToFileName(); }
}
public override object Control {
@ -148,7 +123,6 @@ namespace ICSharpCode.ILSpyAddIn @@ -148,7 +123,6 @@ namespace ICSharpCode.ILSpyAddIn
public override bool IsReadOnly {
get { return true; }
}
#endregion
#region Dispose
@ -158,8 +132,6 @@ namespace ICSharpCode.ILSpyAddIn @@ -158,8 +132,6 @@ namespace ICSharpCode.ILSpyAddIn
codeEditor.Dispose();
SD.BookmarkManager.BookmarkAdded -= BookmarkManager_Added;
SD.BookmarkManager.BookmarkRemoved -= BookmarkManager_Removed;
// DecompileInformation data;
// DebuggerDecompilerService.DebugInformation.TryRemove(decompiledType.MetadataToken.ToInt32(), out data);
base.Dispose();
}
#endregion
@ -197,15 +169,15 @@ namespace ICSharpCode.ILSpyAddIn @@ -197,15 +169,15 @@ namespace ICSharpCode.ILSpyAddIn
#endregion
#region Decompilation
void DecompilationThread()
async void InitializeView()
{
try {
StringWriter writer = new StringWriter();
RunDecompiler(assemblyFile, fullTypeName, new DebuggerTextOutput(new PlainTextOutput(writer)), cancellation.Token);
// if (!cancellation.IsCancellationRequested) {
// SD.MainThread.InvokeAsyncAndForget(() => OnDecompilationFinished(writer));
// }
OnDecompilationFinished(writer);
var parseInformation = await SD.ParserService.ParseAsync(DecompiledTypeName.ToFileName(), cancellationToken: cancellation.Token);
if (parseInformation == null || !(parseInformation.UnresolvedFile is ILSpyUnresolvedFile)) return;
var file = (ILSpyUnresolvedFile)parseInformation.UnresolvedFile;
memberLocations = file.MemberLocations;
DebugSymbols = file.DebugSymbols;
OnDecompilationFinished(file.Output);
} catch (OperationCanceledException) {
// ignore cancellation
} catch (Exception ex) {
@ -216,43 +188,18 @@ namespace ICSharpCode.ILSpyAddIn @@ -216,43 +188,18 @@ namespace ICSharpCode.ILSpyAddIn
SD.AnalyticsMonitor.TrackException(ex);
StringWriter writer = new StringWriter();
writer.WriteLine(string.Format("Exception while decompiling {0} ({1})", fullTypeName, assemblyFile));
writer.WriteLine(string.Format("Exception while decompiling {0} ({1})", DecompiledTypeName.Type, DecompiledTypeName.AssemblyFile));
writer.WriteLine();
writer.WriteLine(ex.ToString());
SD.MainThread.InvokeAsyncAndForget(() => OnDecompilationFinished(writer));
OnDecompilationFinished(writer.ToString());
}
}
void RunDecompiler(string assemblyFile, string fullTypeName, DebuggerTextOutput textOutput, CancellationToken cancellationToken)
{
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions can be garbage-collected
// once the code is decompiled.
readerParameters.AssemblyResolver = new ILSpyAssemblyResolver(Path.GetDirectoryName(assemblyFile));
ModuleDefinition module = ModuleDefinition.ReadModule(assemblyFile, readerParameters);
TypeDefinition typeDefinition = module.GetType(fullTypeName);
if (typeDefinition == null)
throw new InvalidOperationException("Could not find type");
DecompilerContext context = new DecompilerContext(module);
context.CancellationToken = cancellationToken;
AstBuilder astBuilder = new AstBuilder(context);
astBuilder.AddType(typeDefinition);
astBuilder.GenerateCode(textOutput);
// ReflectionDisassembler disasm = new ReflectionDisassembler(textOutput, true, cancellationToken);
// disasm.DisassembleType(typeDefinition);
// save decompilation data
memberLocations = textOutput.MemberLocations;
this.DebugSymbols = textOutput.DebugSymbols;
}
void OnDecompilationFinished(StringWriter output)
void OnDecompilationFinished(string output)
{
if (cancellation.IsCancellationRequested)
return;
codeEditor.Document.Text = output.ToString();
codeEditor.Document.Text = output;
codeEditor.Document.UndoStack.ClearAll();
this.decompilationFinished = true;
@ -280,7 +227,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -280,7 +227,7 @@ namespace ICSharpCode.ILSpyAddIn
codeView.IconBarManager.Bookmarks.Add(bookmark);
}
}
*/
*/
#endregion
#region Bookmarks
@ -296,7 +243,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -296,7 +243,7 @@ namespace ICSharpCode.ILSpyAddIn
void BookmarkManager_Added(object sender, BookmarkEventArgs e)
{
var mark = e.Bookmark;
if (mark != null && mark.FileName == VirtualFileName) {
if (mark != null && mark.FileName == PrimaryFileName) {
codeEditor.IconBarManager.Bookmarks.Add(mark);
mark.Document = this.codeEditor.Document;
}

2
src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast
RunTransformations();
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
var outputFormatter = new TextOutputFormatter(output) { FoldBraces = context.Settings.FoldBraces };
var outputFormatter = new TextTokenWriter(output) { FoldBraces = context.Settings.FoldBraces };
var formattingPolicy = context.Settings.CSharpFormattingOptions;
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy));
}

49
src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs → src/Libraries/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs

@ -27,7 +27,7 @@ using Mono.Cecil; @@ -27,7 +27,7 @@ using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast
{
public class TextOutputFormatter : IOutputFormatter
public class TextTokenWriter : TokenWriter
{
readonly ITextOutput output;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
@ -40,37 +40,37 @@ namespace ICSharpCode.Decompiler.Ast @@ -40,37 +40,37 @@ namespace ICSharpCode.Decompiler.Ast
public bool FoldBraces = false;
public TextOutputFormatter(ITextOutput output)
public TextTokenWriter(ITextOutput output)
{
if (output == null)
throw new ArgumentNullException("output");
this.output = output;
}
public void WriteIdentifier(string identifier)
public override void WriteIdentifier(Identifier identifier)
{
var definition = GetCurrentDefinition();
if (definition != null) {
output.WriteDefinition(identifier, definition, false);
output.WriteDefinition(identifier.Name, definition, false);
return;
}
object memberRef = GetCurrentMemberReference();
if (memberRef != null) {
output.WriteReference(identifier, memberRef);
output.WriteReference(identifier.Name, memberRef);
return;
}
definition = GetCurrentLocalDefinition();
if (definition != null) {
output.WriteDefinition(identifier, definition);
output.WriteDefinition(identifier.Name, definition);
return;
}
memberRef = GetCurrentLocalReference();
if (memberRef != null) {
output.WriteReference(identifier, memberRef, true);
output.WriteReference(identifier.Name, memberRef, true);
return;
}
@ -79,7 +79,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -79,7 +79,7 @@ namespace ICSharpCode.Decompiler.Ast
firstUsingDeclaration = false;
}
output.Write(identifier);
output.Write(identifier.Name);
}
MemberReference GetCurrentMemberReference()
@ -160,12 +160,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -160,12 +160,12 @@ namespace ICSharpCode.Decompiler.Ast
return null;
}
public void WriteKeyword(string keyword)
public override void WriteKeyword(Role role, string keyword)
{
output.Write(keyword);
}
public void WriteToken(string token)
public override void WriteToken(Role role, string token)
{
// Attach member reference to token only if there's no identifier in the current node.
MemberReference memberRef = GetCurrentMemberReference();
@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Ast
output.Write(token);
}
public void Space()
public override void Space()
{
output.Write(' ');
}
@ -203,17 +203,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -203,17 +203,17 @@ namespace ICSharpCode.Decompiler.Ast
braceLevelWithinType--;
}
public void Indent()
public override void Indent()
{
output.Indent();
}
public void Unindent()
public override void Unindent()
{
output.Unindent();
}
public void NewLine()
public override void NewLine()
{
if (lastUsingDeclaration) {
output.MarkFoldEnd();
@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.Ast
output.WriteLine();
}
public void WriteComment(CommentType commentType, string content)
public override void WriteComment(CommentType commentType, string content)
{
switch (commentType) {
case CommentType.SingleLine:
@ -255,7 +255,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -255,7 +255,7 @@ namespace ICSharpCode.Decompiler.Ast
}
}
public void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
// pre-processor directive must start on its own line
output.Write('#');
@ -267,10 +267,23 @@ namespace ICSharpCode.Decompiler.Ast @@ -267,10 +267,23 @@ namespace ICSharpCode.Decompiler.Ast
output.WriteLine();
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
}
public override void WritePrimitiveType(string type)
{
output.Write(type);
if (type == "new") {
output.Write("()");
}
}
Stack<TextLocation> startLocations = new Stack<TextLocation>();
Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public void StartNode(AstNode node)
public override void StartNode(AstNode node)
{
if (nodeStack.Count == 0) {
if (IsUsingDeclaration(node)) {
@ -298,7 +311,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -298,7 +311,7 @@ namespace ICSharpCode.Decompiler.Ast
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
public void EndNode(AstNode node)
public override void EndNode(AstNode node)
{
if (nodeStack.Pop() != node)
throw new InvalidOperationException();

4
src/Libraries/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.Disassembler
} else {
// The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence,
// but we follow Microsoft's ILDasm and use \'.
return "'" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'";
return "'" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(identifier).Replace("'", "\\'") + "'";
}
}
@ -353,7 +353,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -353,7 +353,7 @@ namespace ICSharpCode.Decompiler.Disassembler
string s = operand as string;
if (s != null) {
writer.Write("\"" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(s) + "\"");
writer.Write("\"" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(s) + "\"");
} else if (operand is char) {
writer.Write(((int)(char)operand).ToString());
} else if (operand is float) {

12
src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -126,10 +126,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -126,10 +126,10 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write("pinvokeimpl");
if (method.HasPInvokeInfo && method.PInvokeInfo != null) {
PInvokeInfo info = method.PInvokeInfo;
output.Write("(\"" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(info.Module.Name) + "\"");
output.Write("(\"" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(info.Module.Name) + "\"");
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name)
output.Write(" as \"" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(info.EntryPoint) + "\"");
output.Write(" as \"" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(info.EntryPoint) + "\"");
if (info.IsNoMangle)
output.Write(" nomangle");
@ -346,7 +346,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -346,7 +346,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(" = ");
if (na.Argument.Value is string) {
// secdecls use special syntax for strings
output.Write("string('{0}')", NRefactory.CSharp.CSharpOutputVisitor.ConvertString((string)na.Argument.Value).Replace("'", "\'"));
output.Write("string('{0}')", NRefactory.CSharp.TextWriterTokenWriter.ConvertString((string)na.Argument.Value).Replace("'", "\'"));
} else {
WriteConstant(na.Argument.Value);
}
@ -574,10 +574,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -574,10 +574,10 @@ namespace ICSharpCode.Decompiler.Disassembler
if (cmi == null)
goto default;
output.Write("custom(\"{0}\", \"{1}\"",
NRefactory.CSharp.CSharpOutputVisitor.ConvertString(cmi.ManagedType.FullName),
NRefactory.CSharp.CSharpOutputVisitor.ConvertString(cmi.Cookie));
NRefactory.CSharp.TextWriterTokenWriter.ConvertString(cmi.ManagedType.FullName),
NRefactory.CSharp.TextWriterTokenWriter.ConvertString(cmi.Cookie));
if (cmi.Guid != Guid.Empty || !string.IsNullOrEmpty(cmi.UnmanagedType)) {
output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.CSharpOutputVisitor.ConvertString(cmi.UnmanagedType));
output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.TextWriterTokenWriter.ConvertString(cmi.UnmanagedType));
}
output.Write(')');
break;

2
src/Libraries/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -60,7 +60,7 @@ @@ -60,7 +60,7 @@
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\TextTokenWriter.cs" />
<Compile Include="Ast\Transforms\AddCheckedBlocks.cs" />
<Compile Include="Ast\Transforms\CombineQueryExpressions.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/UseStringFormatAction.cs

@ -114,7 +114,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -114,7 +114,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
format.Append('"');
if (verbatim)
format.Insert(0, '@');
formatLiteral.LiteralValue = format.ToString();
formatLiteral.SetValue(format.ToString(), format.ToString());
if (arguments.Count > 0)
script.Replace(expr, formatInvocation);
else

16
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -411,6 +411,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -411,6 +411,8 @@ namespace ICSharpCode.NRefactory.CSharp
if (child == null || child.IsNull)
return;
ThrowIfFrozen();
if (child == this)
throw new ArgumentException ("Cannot add a node to itself as a child.", "child");
if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child");
if (child.IsFrozen)
@ -418,6 +420,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -418,6 +420,20 @@ namespace ICSharpCode.NRefactory.CSharp
AddChildUnsafe (child, role);
}
public void AddChildWithExistingRole (AstNode child)
{
if (child == null || child.IsNull)
return;
ThrowIfFrozen();
if (child == this)
throw new ArgumentException ("Cannot add a node to itself as a child.", "child");
if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child");
if (child.IsFrozen)
throw new ArgumentException ("Cannot add a frozen node.", "child");
AddChildUnsafe (child, child.Role);
}
/// <summary>
/// Adds a child without performing any safety checks.
/// </summary>

45
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs

@ -169,5 +169,50 @@ namespace ICSharpCode.NRefactory.CSharp @@ -169,5 +169,50 @@ namespace ICSharpCode.NRefactory.CSharp
throw new NotSupportedException("Invalid value for Modifiers");
}
}
public static Modifiers GetModifierValue(string modifier)
{
switch (modifier) {
case "private":
return Modifiers.Private;
case "internal":
return Modifiers.Internal;
case "protected":
return Modifiers.Protected;
case "public":
return Modifiers.Public;
case "abstract":
return Modifiers.Abstract;
case "virtual":
return Modifiers.Virtual;
case "sealed":
return Modifiers.Sealed;
case "static":
return Modifiers.Static;
case "override":
return Modifiers.Override;
case "readonly":
return Modifiers.Readonly;
case "const":
return Modifiers.Const;
case "new":
return Modifiers.New;
case "partial":
return Modifiers.Partial;
case "extern":
return Modifiers.Extern;
case "volatile":
return Modifiers.Volatile;
case "unsafe":
return Modifiers.Unsafe;
case "async":
return Modifiers.Async;
case "any":
// even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
return Modifiers.Any;
default:
throw new NotSupportedException("Invalid value for Modifiers");
}
}
}
}

10
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// NullReferenceExpression.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -38,6 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -38,6 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.location = value;
}
public override TextLocation EndLocation {
get {
return new TextLocation (location.Line, location.Column + "null".Length);
@ -57,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -57,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
visitor.VisitNullReferenceExpression (this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{
return visitor.VisitNullReferenceExpression (this);

47
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// PrimitiveExpression.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -42,13 +42,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -42,13 +42,20 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.startLocation = value;
this.endLocation = null;
}
string literalValue;
TextLocation? endLocation;
public override TextLocation EndLocation {
get {
if (!endLocation.HasValue) {
endLocation = value is string ? AdvanceLocation (StartLocation, literalValue) :
new TextLocation (StartLocation.Line, StartLocation.Column + literalValue.Length);
endLocation = value is string ? AdvanceLocation (StartLocation, literalValue ?? "") :
new TextLocation (StartLocation.Line, StartLocation.Column + (literalValue ?? "").Length);
}
return endLocation.Value;
}
@ -58,46 +65,56 @@ namespace ICSharpCode.NRefactory.CSharp @@ -58,46 +65,56 @@ namespace ICSharpCode.NRefactory.CSharp
public object Value {
get { return this.value; }
set {
ThrowIfFrozen();
set {
ThrowIfFrozen();
this.value = value;
literalValue = null;
}
}
/// <remarks>Never returns null.</remarks>
public string LiteralValue {
get { return literalValue ?? ""; }
}
/// <remarks>Can be null.</remarks>
public string UnsafeLiteralValue {
get { return literalValue; }
set {
if (value == null)
throw new ArgumentNullException();
ThrowIfFrozen();
literalValue = value;
}
}
public void SetValue(object value, string literalValue)
{
if (value == null)
throw new ArgumentNullException();
ThrowIfFrozen();
this.value = value;
this.literalValue = literalValue;
}
public PrimitiveExpression (object value)
{
this.Value = value;
this.literalValue = "";
this.literalValue = null;
}
public PrimitiveExpression (object value, string literalValue)
{
this.Value = value;
this.literalValue = literalValue ?? "";
this.literalValue = literalValue;
}
public PrimitiveExpression (object value, TextLocation startLocation, string literalValue)
{
this.Value = value;
this.startLocation = startLocation;
this.literalValue = literalValue ?? "";
this.literalValue = literalValue;
}
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitPrimitiveExpression (this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{
return visitor.VisitPrimitiveExpression (this);

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs

@ -83,6 +83,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -83,6 +83,12 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.startLocation = value;
}
const uint verbatimBit = 1u << AstNodeFlagsUsedBits;
public bool IsVerbatim {

7
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs

@ -71,6 +71,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -71,6 +71,13 @@ namespace ICSharpCode.NRefactory.CSharp
return location;
}
}
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.location = value;
}
public override TextLocation EndLocation {
get {
return new TextLocation (location.Line, location.Column + keyword.Length);

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -209,9 +209,12 @@ @@ -209,9 +209,12 @@
<Compile Include="Formatter\Indent.cs" />
<Compile Include="OutputVisitor\CodeDomConvertVisitor.cs" />
<Compile Include="OutputVisitor\CSharpAmbience.cs" />
<Compile Include="OutputVisitor\InsertMissingTokensDecorator.cs" />
<Compile Include="OutputVisitor\InsertParenthesesVisitor.cs" />
<Compile Include="OutputVisitor\IOutputFormatter.cs" />
<Compile Include="OutputVisitor\InsertRequiredSpacesDecorator.cs" />
<Compile Include="OutputVisitor\CSharpOutputVisitor.cs" />
<Compile Include="OutputVisitor\InsertSpecialsDecorator.cs" />
<Compile Include="OutputVisitor\ITokenWriter.cs" />
<Compile Include="OutputVisitor\TextWriterOutputFormatter.cs" />
<Compile Include="Parser\CompilerSettings.cs" />
<Compile Include="Parser\CSharpParser.cs" />

153
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs

@ -37,98 +37,98 @@ namespace ICSharpCode.NRefactory.CSharp @@ -37,98 +37,98 @@ namespace ICSharpCode.NRefactory.CSharp
throw new ArgumentNullException("entity");
StringWriter writer = new StringWriter();
ConvertEntity(entity, new TextWriterOutputFormatter(writer), FormattingOptionsFactory.CreateMono ());
ConvertEntity(entity, new TextWriterTokenWriter(writer), FormattingOptionsFactory.CreateMono ());
return writer.ToString();
}
public void ConvertEntity(IEntity entity, IOutputFormatter formatter, CSharpFormattingOptions formattingPolicy)
public void ConvertEntity(IEntity entity, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
if (entity == null)
throw new ArgumentNullException("entity");
if (formatter == null)
throw new ArgumentNullException("formatter");
if (writer == null)
throw new ArgumentNullException("writer");
if (formattingPolicy == null)
throw new ArgumentNullException("options");
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(entity);
PrintModifiers(node.Modifiers, formatter);
PrintModifiers(node.Modifiers, writer);
if ((ConversionFlags & ConversionFlags.ShowDefinitionKeyword) == ConversionFlags.ShowDefinitionKeyword) {
if (node is TypeDeclaration) {
switch (((TypeDeclaration)node).ClassType) {
case ClassType.Class:
formatter.WriteKeyword("class");
writer.WriteKeyword(Roles.ClassKeyword, "class");
break;
case ClassType.Struct:
formatter.WriteKeyword("struct");
writer.WriteKeyword(Roles.StructKeyword, "struct");
break;
case ClassType.Interface:
formatter.WriteKeyword("interface");
writer.WriteKeyword(Roles.InterfaceKeyword, "interface");
break;
case ClassType.Enum:
formatter.WriteKeyword("enum");
writer.WriteKeyword(Roles.EnumKeyword, "enum");
break;
default:
throw new Exception("Invalid value for ClassType");
}
formatter.Space();
writer.Space();
} else if (node is DelegateDeclaration) {
formatter.WriteKeyword("delegate");
formatter.Space();
writer.WriteKeyword(Roles.DelegateKeyword, "delegate");
writer.Space();
} else if (node is EventDeclaration) {
formatter.WriteKeyword("event");
formatter.Space();
writer.WriteKeyword(EventDeclaration.EventKeywordRole, "event");
writer.Space();
}
}
if ((ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) {
var rt = node.GetChildByRole(Roles.Type);
if (!rt.IsNull) {
rt.AcceptVisitor(new CSharpOutputVisitor(formatter, formattingPolicy));
formatter.Space();
rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
writer.Space();
}
}
if (entity is ITypeDefinition)
WriteTypeDeclarationName((ITypeDefinition)entity, formatter, formattingPolicy);
WriteTypeDeclarationName((ITypeDefinition)entity, writer, formattingPolicy);
else
WriteMemberDeclarationName((IMember)entity, formatter, formattingPolicy);
WriteMemberDeclarationName((IMember)entity, writer, formattingPolicy);
if ((ConversionFlags & ConversionFlags.ShowParameterList) == ConversionFlags.ShowParameterList && HasParameters(entity)) {
formatter.WriteToken(entity.SymbolKind == SymbolKind.Indexer ? "[" : "(");
writer.WriteToken(entity.SymbolKind == SymbolKind.Indexer ? Roles.LBracket : Roles.LPar, entity.SymbolKind == SymbolKind.Indexer ? "[" : "(");
bool first = true;
foreach (var param in node.GetChildrenByRole(Roles.Parameter)) {
if (first) {
first = false;
} else {
formatter.WriteToken(",");
formatter.Space();
writer.WriteToken(Roles.Comma, ",");
writer.Space();
}
param.AcceptVisitor(new CSharpOutputVisitor(formatter, formattingPolicy));
param.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
}
formatter.WriteToken(entity.SymbolKind == SymbolKind.Indexer ? "]" : ")");
writer.WriteToken(entity.SymbolKind == SymbolKind.Indexer ? Roles.RBracket : Roles.RPar, entity.SymbolKind == SymbolKind.Indexer ? "]" : ")");
}
if ((ConversionFlags & ConversionFlags.ShowBody) == ConversionFlags.ShowBody && !(node is TypeDeclaration)) {
IProperty property = entity as IProperty;
if (property != null) {
formatter.Space();
formatter.WriteToken("{");
formatter.Space();
writer.Space();
writer.WriteToken(Roles.LBrace, "{");
writer.Space();
if (property.CanGet) {
formatter.WriteKeyword("get");
formatter.WriteToken(";");
formatter.Space();
writer.WriteKeyword(PropertyDeclaration.GetKeywordRole, "get");
writer.WriteToken(Roles.Semicolon, ";");
writer.Space();
}
if (property.CanSet) {
formatter.WriteKeyword("set");
formatter.WriteToken(";");
formatter.Space();
writer.WriteKeyword(PropertyDeclaration.SetKeywordRole, "set");
writer.WriteToken(Roles.Semicolon, ";");
writer.Space();
}
formatter.WriteToken("}");
writer.WriteToken(Roles.RBrace, "}");
} else {
formatter.WriteToken(";");
writer.WriteToken(Roles.Semicolon, ";");
}
}
}
@ -160,87 +160,96 @@ namespace ICSharpCode.NRefactory.CSharp @@ -160,87 +160,96 @@ namespace ICSharpCode.NRefactory.CSharp
return astBuilder;
}
void WriteTypeDeclarationName(ITypeDefinition typeDef, IOutputFormatter formatter, CSharpFormattingOptions formattingPolicy)
void WriteTypeDeclarationName(ITypeDefinition typeDef, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(typeDef);
if (typeDef.DeclaringTypeDefinition != null) {
WriteTypeDeclarationName(typeDef.DeclaringTypeDefinition, formatter, formattingPolicy);
formatter.WriteToken(".");
WriteTypeDeclarationName(typeDef.DeclaringTypeDefinition, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
} else if ((ConversionFlags & ConversionFlags.UseFullyQualifiedTypeNames) == ConversionFlags.UseFullyQualifiedTypeNames) {
formatter.WriteIdentifier(typeDef.Namespace);
formatter.WriteToken(".");
WriteQualifiedName(typeDef.Namespace, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
formatter.WriteIdentifier(typeDef.Name);
writer.WriteIdentifier(node.NameToken);
if ((ConversionFlags & ConversionFlags.ShowTypeParameterList) == ConversionFlags.ShowTypeParameterList) {
var outputVisitor = new CSharpOutputVisitor(formatter, formattingPolicy);
outputVisitor.WriteTypeParameters(astBuilder.ConvertEntity(typeDef).GetChildrenByRole(Roles.TypeParameter));
var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
outputVisitor.WriteTypeParameters(node.GetChildrenByRole(Roles.TypeParameter));
}
}
void WriteMemberDeclarationName(IMember member, IOutputFormatter formatter, CSharpFormattingOptions formattingPolicy)
void WriteMemberDeclarationName(IMember member, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(member);
if ((ConversionFlags & ConversionFlags.ShowDeclaringType) == ConversionFlags.ShowDeclaringType) {
ConvertType(member.DeclaringType, formatter, formattingPolicy);
formatter.WriteToken(".");
ConvertType(member.DeclaringType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
switch (member.SymbolKind) {
case SymbolKind.Indexer:
formatter.WriteKeyword("this");
writer.WriteKeyword(Roles.Identifier, "this");
break;
case SymbolKind.Constructor:
formatter.WriteIdentifier(member.DeclaringType.Name);
WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
break;
case SymbolKind.Destructor:
formatter.WriteToken("~");
formatter.WriteIdentifier(member.DeclaringType.Name);
writer.WriteToken(DestructorDeclaration.TildeRole, "~");
WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
break;
case SymbolKind.Operator:
switch (member.Name) {
case "op_Implicit":
formatter.WriteKeyword("implicit");
formatter.Space();
formatter.WriteKeyword("operator");
formatter.Space();
ConvertType(member.ReturnType, formatter, formattingPolicy);
writer.WriteKeyword(OperatorDeclaration.ImplicitRole, "implicit");
writer.Space();
writer.WriteKeyword(OperatorDeclaration.OperatorKeywordRole, "operator");
writer.Space();
ConvertType(member.ReturnType, writer, formattingPolicy);
break;
case "op_Explicit":
formatter.WriteKeyword("explicit");
formatter.Space();
formatter.WriteKeyword("operator");
formatter.Space();
ConvertType(member.ReturnType, formatter, formattingPolicy);
writer.WriteKeyword(OperatorDeclaration.ExplicitRole, "explicit");
writer.Space();
writer.WriteKeyword(OperatorDeclaration.OperatorKeywordRole, "operator");
writer.Space();
ConvertType(member.ReturnType, writer, formattingPolicy);
break;
default:
formatter.WriteKeyword("operator");
formatter.Space();
writer.WriteKeyword(OperatorDeclaration.OperatorKeywordRole, "operator");
writer.Space();
var operatorType = OperatorDeclaration.GetOperatorType(member.Name);
if (operatorType.HasValue)
formatter.WriteToken(OperatorDeclaration.GetToken(operatorType.Value));
writer.WriteToken(OperatorDeclaration.GetRole(operatorType.Value), OperatorDeclaration.GetToken(operatorType.Value));
else
formatter.WriteIdentifier(member.Name);
writer.WriteIdentifier(node.NameToken);
break;
}
break;
default:
formatter.WriteIdentifier(member.Name);
writer.WriteIdentifier(Identifier.Create(member.Name));
break;
}
if ((ConversionFlags & ConversionFlags.ShowTypeParameterList) == ConversionFlags.ShowTypeParameterList && member.SymbolKind == SymbolKind.Method) {
var outputVisitor = new CSharpOutputVisitor(formatter, formattingPolicy);
outputVisitor.WriteTypeParameters(astBuilder.ConvertEntity(member).GetChildrenByRole(Roles.TypeParameter));
var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
outputVisitor.WriteTypeParameters(node.GetChildrenByRole(Roles.TypeParameter));
}
}
void PrintModifiers(Modifiers modifiers, IOutputFormatter formatter)
void PrintModifiers(Modifiers modifiers, TokenWriter writer)
{
foreach (var m in CSharpModifierToken.AllModifiers) {
if ((modifiers & m) == m) {
formatter.WriteKeyword(CSharpModifierToken.GetModifierName(m));
formatter.Space();
writer.WriteKeyword(EntityDeclaration.ModifierRole, CSharpModifierToken.GetModifierName(m));
writer.Space();
}
}
}
void WriteQualifiedName(string name, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
var node = AstType.Create(name);
var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
node.AcceptVisitor(outputVisitor);
}
#endregion
public string ConvertVariable(IVariable v)
@ -260,16 +269,16 @@ namespace ICSharpCode.NRefactory.CSharp @@ -260,16 +269,16 @@ namespace ICSharpCode.NRefactory.CSharp
return astType.ToString();
}
public void ConvertType(IType type, IOutputFormatter formatter, CSharpFormattingOptions formattingPolicy)
public void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
AstType astType = astBuilder.ConvertType(type);
astType.AcceptVisitor(new CSharpOutputVisitor(formatter, formattingPolicy));
astType.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
}
public string ConvertConstantValue(object constantValue)
{
return CSharpOutputVisitor.PrintPrimitiveValue(constantValue);
return TextWriterTokenWriter.PrintPrimitiveValue(constantValue);
}
public string WrapComment(string comment)

629
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

File diff suppressed because it is too large Load Diff

60
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/IOutputFormatter.cs

@ -1,60 +0,0 @@ @@ -1,60 +0,0 @@
// Copyright (c) 2010-2013 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;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Output formatter for the Output visitor.
/// </summary>
public interface IOutputFormatter
{
void StartNode(AstNode node);
void EndNode(AstNode node);
/// <summary>
/// Writes an identifier.
/// If the identifier conflicts with a keyword, the output visitor will
/// call <c>WriteToken("@")</c> before calling WriteIdentifier().
/// </summary>
void WriteIdentifier(string identifier);
/// <summary>
/// Writes a keyword to the output.
/// </summary>
void WriteKeyword(string keyword);
/// <summary>
/// Writes a token to the output.
/// </summary>
void WriteToken(string token);
void Space();
void OpenBrace(BraceStyle style);
void CloseBrace(BraceStyle style);
void Indent();
void Unindent();
void NewLine();
void WriteComment(CommentType commentType, string content);
void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument);
}
}

161
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/ITokenWriter.cs

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
// Copyright (c) 2010-2013 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.IO;
namespace ICSharpCode.NRefactory.CSharp
{
public abstract class TokenWriter
{
public abstract void StartNode(AstNode node);
public abstract void EndNode(AstNode node);
/// <summary>
/// Writes an identifier.
/// </summary>
public abstract void WriteIdentifier(Identifier identifier);
/// <summary>
/// Writes a keyword to the output.
/// </summary>
public abstract void WriteKeyword(Role role, string keyword);
/// <summary>
/// Writes a token to the output.
/// </summary>
public abstract void WriteToken(Role role, string token);
/// <summary>
/// Writes a primitive/literal value
/// </summary>
public abstract void WritePrimitiveValue(object value, string literalValue = null);
public abstract void WritePrimitiveType(string type);
public abstract void Space();
public abstract void Indent();
public abstract void Unindent();
public abstract void NewLine();
public abstract void WriteComment(CommentType commentType, string content);
public abstract void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument);
public static TokenWriter Create(TextWriter writer, string indentation = "\t")
{
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new TextWriterTokenWriter(writer) { IndentationString = indentation }));
}
public static TokenWriter CreateWriterThatSetsLocationsInAST(TextWriter writer, string indentation = "\t")
{
var target = new TextWriterTokenWriter(writer) { IndentationString = indentation };
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new InsertMissingTokensDecorator(target, target)));
}
public static TokenWriter WrapInWriterThatSetsLocationsInAST(TokenWriter writer)
{
if (!(writer is ILocatable))
throw new InvalidOperationException("writer does not provide locations!");
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new InsertMissingTokensDecorator(writer, (ILocatable)writer)));
}
}
public interface ILocatable
{
TextLocation Location { get; }
}
public abstract class DecoratingTokenWriter : TokenWriter
{
TokenWriter decoratedWriter;
protected DecoratingTokenWriter(TokenWriter decoratedWriter)
{
if (decoratedWriter == null)
throw new ArgumentNullException("decoratedWriter");
this.decoratedWriter = decoratedWriter;
}
public override void StartNode(AstNode node)
{
decoratedWriter.StartNode(node);
}
public override void EndNode(AstNode node)
{
decoratedWriter.EndNode(node);
}
public override void WriteIdentifier(Identifier identifier)
{
decoratedWriter.WriteIdentifier(identifier);
}
public override void WriteKeyword(Role role, string keyword)
{
decoratedWriter.WriteKeyword(role, keyword);
}
public override void WriteToken(Role role, string token)
{
decoratedWriter.WriteToken(role, token);
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
decoratedWriter.WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)
{
decoratedWriter.WritePrimitiveType(type);
}
public override void Space()
{
decoratedWriter.Space();
}
public override void Indent()
{
decoratedWriter.Indent();
}
public override void Unindent()
{
decoratedWriter.Unindent();
}
public override void NewLine()
{
decoratedWriter.NewLine();
}
public override void WriteComment(CommentType commentType, string content)
{
decoratedWriter.WriteComment(commentType, content);
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
decoratedWriter.WritePreProcessorDirective(type, argument);
}
}
}

122
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertMissingTokensDecorator.cs

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
// Copyright (c) 2010-2013 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.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
class InsertMissingTokensDecorator : DecoratingTokenWriter
{
readonly Stack<List<AstNode>> nodes = new Stack<List<AstNode>>();
List<AstNode> currentList;
readonly ILocatable locationProvider;
public InsertMissingTokensDecorator(TokenWriter writer, ILocatable locationProvider)
: base(writer)
{
this.locationProvider = locationProvider;
currentList = new List<AstNode>();
}
public override void StartNode(AstNode node)
{
currentList.Add(node);
nodes.Push(currentList);
currentList = new List<AstNode>();
base.StartNode(node);
}
public override void EndNode(AstNode node)
{
System.Diagnostics.Debug.Assert(currentList != null);
foreach (var removable in node.Children.Where(n => n is CSharpTokenNode)) {
removable.Remove();
}
foreach (var child in currentList) {
System.Diagnostics.Debug.Assert(child.Parent == null || node == child.Parent);
child.Remove();
node.AddChildWithExistingRole(child);
}
currentList = nodes.Pop();
base.EndNode(node);
}
public override void WriteToken(Role role, string token)
{
CSharpTokenNode t = new CSharpTokenNode(locationProvider.Location, (TokenRole)role);
EmptyStatement node = nodes.Peek().LastOrDefault() as EmptyStatement;
if (node == null)
currentList.Add(t);
else {
node.Location = locationProvider.Location;
}
base.WriteToken(role, token);
}
public override void WriteKeyword(Role role, string keyword)
{
TextLocation start = locationProvider.Location;
CSharpTokenNode t = null;
if (role is TokenRole)
t = new CSharpTokenNode(start, (TokenRole)role);
else if (role == EntityDeclaration.ModifierRole)
t = new CSharpModifierToken(start, CSharpModifierToken.GetModifierValue(keyword));
else if (keyword == "this") {
ThisReferenceExpression node = nodes.Peek().LastOrDefault() as ThisReferenceExpression;
if (node != null)
node.Location = start;
} else if (keyword == "base") {
BaseReferenceExpression node = nodes.Peek().LastOrDefault() as BaseReferenceExpression;
if (node != null)
node.Location = start;
}
if (t != null) currentList.Add(t);
base.WriteKeyword(role, keyword);
}
public override void WriteIdentifier(Identifier identifier)
{
if (!identifier.IsNull)
identifier.SetStartLocation(locationProvider.Location);
currentList.Add(identifier);
base.WriteIdentifier(identifier);
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
Expression node = nodes.Peek().LastOrDefault() as Expression;
if (node is PrimitiveExpression) {
((PrimitiveExpression)node).SetStartLocation(locationProvider.Location);
}
if (node is NullReferenceExpression) {
((NullReferenceExpression)node).SetStartLocation(locationProvider.Location);
}
base.WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)
{
PrimitiveType node = nodes.Peek().LastOrDefault() as PrimitiveType;
if (node != null)
node.SetStartLocation(locationProvider.Location);
base.WritePrimitiveType(type);
}
}
}

184
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertRequiredSpacesDecorator.cs

@ -0,0 +1,184 @@ @@ -0,0 +1,184 @@
// Copyright (c) 2010-2013 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.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.NRefactory.CSharp
{
class InsertRequiredSpacesDecorator : DecoratingTokenWriter
{
/// <summary>
/// Used to insert the minimal amount of spaces so that the lexer recognizes the tokens that were written.
/// </summary>
LastWritten lastWritten;
enum LastWritten
{
Whitespace,
Other,
KeywordOrIdentifier,
Plus,
Minus,
Ampersand,
QuestionMark,
Division
}
public InsertRequiredSpacesDecorator(TokenWriter writer)
: base(writer)
{
}
public override void WriteIdentifier(Identifier identifier)
{
if (identifier.IsVerbatim) {
if (lastWritten == LastWritten.KeywordOrIdentifier) {
// this space is not strictly required, so we call Space()
Space();
}
} else if (lastWritten == LastWritten.KeywordOrIdentifier) {
// this space is strictly required, so we directly call the formatter
base.Space();
}
base.WriteIdentifier(identifier);
lastWritten = LastWritten.KeywordOrIdentifier;
}
public override void WriteKeyword(Role role, string keyword)
{
if (lastWritten == LastWritten.KeywordOrIdentifier) {
Space();
}
base.WriteKeyword(role, keyword);
lastWritten = LastWritten.KeywordOrIdentifier;
}
public override void WriteToken(Role role, string token)
{
// Avoid that two +, - or ? tokens are combined into a ++, -- or ?? token.
// Note that we don't need to handle tokens like = because there's no valid
// C# program that contains the single token twice in a row.
// (for +, - and &, this can happen with unary operators;
// for ?, this can happen in "a is int? ? b : c" or "a as int? ?? 0";
// and for /, this can happen with "1/ *ptr" or "1/ //comment".)
if (lastWritten == LastWritten.Plus && token[0] == '+' ||
lastWritten == LastWritten.Minus && token[0] == '-' ||
lastWritten == LastWritten.Ampersand && token[0] == '&' ||
lastWritten == LastWritten.QuestionMark && token[0] == '?' ||
lastWritten == LastWritten.Division && token[0] == '*') {
base.Space();
}
base.WriteToken(role, token);
if (token == "+") {
lastWritten = LastWritten.Plus;
} else if (token == "-") {
lastWritten = LastWritten.Minus;
} else if (token == "&") {
lastWritten = LastWritten.Ampersand;
} else if (token == "?") {
lastWritten = LastWritten.QuestionMark;
} else if (token == "/") {
lastWritten = LastWritten.Division;
} else {
lastWritten = LastWritten.Other;
}
}
public override void Space()
{
base.Space();
lastWritten = LastWritten.Whitespace;
}
public override void NewLine()
{
base.NewLine();
lastWritten = LastWritten.Whitespace;
}
public override void WriteComment(CommentType commentType, string content)
{
if (lastWritten == LastWritten.Division) {
// When there's a comment starting after a division operator
// "1.0 / /*comment*/a", then we need to insert a space in front of the comment.
base.Space();
}
base.WriteComment(commentType, content);
lastWritten = LastWritten.Whitespace;
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
base.WritePreProcessorDirective(type, argument);
lastWritten = LastWritten.Whitespace;
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
base.WritePrimitiveValue(value, literalValue);
if (value == null || value is bool)
return;
if (value is string) {
lastWritten = LastWritten.Other;
} else if (value is char) {
lastWritten = LastWritten.Other;
} else if (value is decimal) {
lastWritten = LastWritten.Other;
} else if (value is float) {
float f = (float)value;
if (float.IsInfinity(f) || float.IsNaN(f)) return;
lastWritten = LastWritten.Other;
} else if (value is double) {
double f = (double)value;
if (double.IsInfinity(f) || double.IsNaN(f)) return;
// needs space if identifier follows number;
// this avoids mistaking the following identifier as type suffix
lastWritten = LastWritten.KeywordOrIdentifier;
} else if (value is IFormattable) {
// needs space if identifier follows number;
// this avoids mistaking the following identifier as type suffix
lastWritten = LastWritten.KeywordOrIdentifier;
} else {
lastWritten = LastWritten.Other;
}
}
public override void WritePrimitiveType(string type)
{
if (lastWritten == LastWritten.KeywordOrIdentifier) {
Space();
}
base.WritePrimitiveType(type);
if (type == "new") {
lastWritten = LastWritten.Other;
} else {
lastWritten = LastWritten.KeywordOrIdentifier;
}
}
}
}

157
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertSpecialsDecorator.cs

@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
// Copyright (c) 2010-2013 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.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.NRefactory.CSharp
{
class InsertSpecialsDecorator : DecoratingTokenWriter
{
readonly Stack<AstNode> positionStack = new Stack<AstNode>();
int visitorWroteNewLine = 0;
public InsertSpecialsDecorator(TokenWriter writer) : base(writer)
{
}
public override void StartNode(AstNode node)
{
if (positionStack.Count > 0) {
WriteSpecialsUpToNode(node);
}
positionStack.Push(node.FirstChild);
base.StartNode(node);
}
public override void EndNode(AstNode node)
{
base.EndNode(node);
AstNode pos = positionStack.Pop();
Debug.Assert(pos == null || pos.Parent == node);
WriteSpecials(pos, null);
}
public override void WriteKeyword(Role role, string keyword)
{
if (role != null) {
WriteSpecialsUpToRole(role);
}
base.WriteKeyword(role, keyword);
}
public override void WriteIdentifier(Identifier identifier)
{
WriteSpecialsUpToRole(identifier.Role ?? Roles.Identifier);
base.WriteIdentifier(identifier);
}
public override void WriteToken(Role role, string token)
{
WriteSpecialsUpToRole(role);
base.WriteToken(role, token);
}
public override void NewLine()
{
if (visitorWroteNewLine >= 0)
base.NewLine();
visitorWroteNewLine++;
}
#region WriteSpecials
/// <summary>
/// Writes all specials from start to end (exclusive). Does not touch the positionStack.
/// </summary>
void WriteSpecials(AstNode start, AstNode end)
{
for (AstNode pos = start; pos != end; pos = pos.NextSibling) {
if (pos.Role == Roles.Comment) {
var node = (Comment)pos;
base.WriteComment(node.CommentType, node.Content);
}
// see CSharpOutputVisitor.VisitNewLine()
// if (pos.Role == Roles.NewLine) {
// if (visitorWroteNewLine <= 0)
// base.NewLine();
// visitorWroteNewLine--;
// }
if (pos.Role == Roles.PreProcessorDirective) {
var node = (PreProcessorDirective)pos;
base.WritePreProcessorDirective(node.Type, node.Argument);
}
}
}
/// <summary>
/// Writes all specials between the current position (in the positionStack) and the next
/// node with the specified role. Advances the current position.
/// </summary>
void WriteSpecialsUpToRole(Role role)
{
WriteSpecialsUpToRole(role, null);
}
void WriteSpecialsUpToRole(Role role, AstNode nextNode)
{
if (positionStack.Count == 0) {
return;
}
// Look for the role between the current position and the nextNode.
for (AstNode pos = positionStack.Peek(); pos != null && pos != nextNode; pos = pos.NextSibling) {
if (pos.Role == role) {
WriteSpecials(positionStack.Pop(), pos);
// Push the next sibling because the node matching the role is not a special,
// and should be considered to be already handled.
positionStack.Push(pos.NextSibling);
// This is necessary for OptionalComma() to work correctly.
break;
}
}
}
/// <summary>
/// Writes all specials between the current position (in the positionStack) and the specified node.
/// Advances the current position.
/// </summary>
void WriteSpecialsUpToNode(AstNode node)
{
if (positionStack.Count == 0) {
return;
}
for (AstNode pos = positionStack.Peek(); pos != null; pos = pos.NextSibling) {
if (pos == node) {
WriteSpecials(positionStack.Pop(), pos);
// Push the next sibling because the node itself is not a special,
// and should be considered to be already handled.
positionStack.Push(pos.NextSibling);
// This is necessary for OptionalComma() to work correctly.
break;
}
}
}
#endregion
}
}

359
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/TextWriterOutputFormatter.cs

@ -17,139 +17,79 @@ @@ -17,139 +17,79 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Globalization;
using System.IO;
using System.Text;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Writes C# code into a TextWriter.
/// </summary>
public class TextWriterOutputFormatter : IOutputFormatter
public class TextWriterTokenWriter : TokenWriter, ILocatable
{
readonly TextWriter textWriter;
int indentation;
bool needsIndent = true;
bool isAtStartOfLine = true;
int line, column;
public int Indentation {
get {
return this.indentation;
}
set {
this.indentation = value;
}
get { return this.indentation; }
set { this.indentation = value; }
}
public TextLocation Location {
get { return new TextLocation(line, column + (needsIndent ? indentation * IndentationString.Length : 0)); }
}
public string IndentationString { get; set; }
public TextWriterOutputFormatter(TextWriter textWriter)
public TextWriterTokenWriter(TextWriter textWriter)
{
if (textWriter == null)
throw new ArgumentNullException("textWriter");
this.textWriter = textWriter;
this.IndentationString = "\t";
this.line = 1;
this.column = 1;
}
public void WriteIdentifier(string ident)
public override void WriteIdentifier(Identifier identifier)
{
WriteIndentation();
textWriter.Write(ident);
if (identifier.IsVerbatim) {
textWriter.Write('@');
column++;
}
textWriter.Write(identifier.Name);
column += identifier.Name.Length;
isAtStartOfLine = false;
}
public void WriteKeyword(string keyword)
public override void WriteKeyword(Role role, string keyword)
{
WriteIndentation();
column += keyword.Length;
textWriter.Write(keyword);
isAtStartOfLine = false;
}
public void WriteToken(string token)
public override void WriteToken(Role role, string token)
{
WriteIndentation();
column += token.Length;
textWriter.Write(token);
isAtStartOfLine = false;
}
public void Space()
public override void Space()
{
WriteIndentation();
column++;
textWriter.Write(' ');
}
public void OpenBrace(BraceStyle style)
{
switch (style) {
case BraceStyle.DoNotChange:
case BraceStyle.EndOfLine:
case BraceStyle.BannerStyle:
WriteIndentation();
if (!isAtStartOfLine)
textWriter.Write(' ');
textWriter.Write('{');
break;
case BraceStyle.EndOfLineWithoutSpace:
WriteIndentation();
textWriter.Write('{');
break;
case BraceStyle.NextLine:
if (!isAtStartOfLine)
NewLine();
WriteIndentation();
textWriter.Write('{');
break;
case BraceStyle.NextLineShifted:
NewLine ();
Indent();
WriteIndentation();
textWriter.Write('{');
NewLine();
return;
case BraceStyle.NextLineShifted2:
NewLine ();
Indent();
WriteIndentation();
textWriter.Write('{');
break;
default:
throw new ArgumentOutOfRangeException ();
}
Indent();
NewLine();
}
public void CloseBrace(BraceStyle style)
{
switch (style) {
case BraceStyle.DoNotChange:
case BraceStyle.EndOfLine:
case BraceStyle.EndOfLineWithoutSpace:
case BraceStyle.NextLine:
Unindent();
WriteIndentation();
textWriter.Write('}');
isAtStartOfLine = false;
break;
case BraceStyle.BannerStyle:
case BraceStyle.NextLineShifted:
WriteIndentation();
textWriter.Write('}');
isAtStartOfLine = false;
Unindent();
break;
case BraceStyle.NextLineShifted2:
Unindent();
WriteIndentation();
textWriter.Write('}');
isAtStartOfLine = false;
Unindent();
break;
default:
throw new ArgumentOutOfRangeException ();
}
}
protected void WriteIndentation()
{
if (needsIndent) {
@ -157,33 +97,37 @@ namespace ICSharpCode.NRefactory.CSharp @@ -157,33 +97,37 @@ namespace ICSharpCode.NRefactory.CSharp
for (int i = 0; i < indentation; i++) {
textWriter.Write(this.IndentationString);
}
column += indentation * IndentationString.Length;
}
}
public void NewLine()
public override void NewLine()
{
textWriter.WriteLine();
column = 1;
line++;
needsIndent = true;
isAtStartOfLine = true;
}
public void Indent()
public override void Indent()
{
indentation++;
}
public void Unindent()
public override void Unindent()
{
indentation--;
}
public void WriteComment(CommentType commentType, string content)
public override void WriteComment(CommentType commentType, string content)
{
WriteIndentation();
switch (commentType) {
case CommentType.SingleLine:
textWriter.Write("//");
textWriter.WriteLine(content);
column += 2 + content.Length;
needsIndent = true;
isAtStartOfLine = true;
break;
@ -191,36 +135,263 @@ namespace ICSharpCode.NRefactory.CSharp @@ -191,36 +135,263 @@ namespace ICSharpCode.NRefactory.CSharp
textWriter.Write("/*");
textWriter.Write(content);
textWriter.Write("*/");
column += 2;
UpdateEndLocation(content, ref line, ref column);
column += 2;
isAtStartOfLine = false;
break;
case CommentType.Documentation:
textWriter.Write("///");
textWriter.WriteLine(content);
column += 3 + content.Length;
needsIndent = true;
isAtStartOfLine = true;
break;
default:
textWriter.Write(content);
column += content.Length;
break;
}
}
public void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
static void UpdateEndLocation(string content, ref int line, ref int column)
{
if (string.IsNullOrEmpty(content))
return;
for (int i = 0; i < content.Length; i++) {
char ch = content[i];
switch (ch) {
case '\r':
if (i + 1 < content.Length && content[i + 1] == '\n')
i++;
goto case '\n';
case '\n':
line++;
column = 0;
break;
}
column++;
}
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{
// pre-processor directive must start on its own line
if (!isAtStartOfLine)
NewLine();
WriteIndentation();
textWriter.Write('#');
textWriter.Write(type.ToString().ToLowerInvariant());
string directive = type.ToString().ToLowerInvariant();
textWriter.Write(directive);
column += 1 + directive.Length;
if (!string.IsNullOrEmpty(argument)) {
textWriter.Write(' ');
textWriter.Write(argument);
column += 1 + argument.Length;
}
NewLine();
}
public virtual void StartNode(AstNode node)
public static string PrintPrimitiveValue(object value)
{
TextWriter writer = new StringWriter();
TextWriterTokenWriter tokenWriter = new TextWriterTokenWriter(writer);
tokenWriter.WritePrimitiveValue(value);
return writer.ToString();
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
if (literalValue != null) {
textWriter.Write(literalValue);
column += literalValue.Length;
return;
}
if (value == null) {
// usually NullReferenceExpression should be used for this, but we'll handle it anyways
textWriter.Write("null");
column += 4;
return;
}
if (value is bool) {
if ((bool)value) {
textWriter.Write("true");
column += 4;
} else {
textWriter.Write("false");
column += 5;
}
return;
}
if (value is string) {
string tmp = "\"" + ConvertString(value.ToString()) + "\"";
column += tmp.Length;
textWriter.Write(tmp);
} else if (value is char) {
string tmp = "'" + ConvertCharLiteral((char)value) + "'";
column += tmp.Length;
textWriter.Write(tmp);
} else if (value is decimal) {
string str = ((decimal)value).ToString(NumberFormatInfo.InvariantInfo) + "m";
column += str.Length;
textWriter.Write(str);
} else if (value is float) {
float f = (float)value;
if (float.IsInfinity(f) || float.IsNaN(f)) {
// Strictly speaking, these aren't PrimitiveExpressions;
// but we still support writing these to make life easier for code generators.
textWriter.Write("float");
column += 5;
WriteToken(Roles.Dot, ".");
if (float.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
} else if (float.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
} else {
textWriter.Write("NaN");
column += 3;
}
return;
}
if (f == 0 && 1 / f == float.NegativeInfinity) {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
textWriter.Write("-");
column++;
}
var str = f.ToString("R", NumberFormatInfo.InvariantInfo) + "f";
column += str.Length;
textWriter.Write(str);
} else if (value is double) {
double f = (double)value;
if (double.IsInfinity(f) || double.IsNaN(f)) {
// Strictly speaking, these aren't PrimitiveExpressions;
// but we still support writing these to make life easier for code generators.
textWriter.Write("double");
column += 6;
WriteToken(Roles.Dot, ".");
if (double.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
} else if (double.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
} else {
textWriter.Write("NaN");
column += 3;
}
return;
}
if (f == 0 && 1 / f == double.NegativeInfinity) {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
textWriter.Write("-");
}
string number = f.ToString("R", NumberFormatInfo.InvariantInfo);
if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) {
number += ".0";
}
textWriter.Write(number);
} else if (value is IFormattable) {
StringBuilder b = new StringBuilder ();
// if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) {
// b.Append("0x");
// b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo));
// } else {
b.Append(((IFormattable)value).ToString(null, NumberFormatInfo.InvariantInfo));
// }
if (value is uint || value is ulong) {
b.Append("u");
}
if (value is long || value is ulong) {
b.Append("L");
}
textWriter.Write(b.ToString());
column += b.Length;
} else {
textWriter.Write(value.ToString());
column += value.ToString().Length;
}
}
static string ConvertCharLiteral(char ch)
{
if (ch == '\'') {
return "\\'";
}
return ConvertChar(ch);
}
/// <summary>
/// Gets the escape sequence for the specified character.
/// </summary>
/// <remarks>This method does not convert ' or ".</remarks>
public static string ConvertChar(char ch)
{
switch (ch) {
case '\\':
return "\\\\";
case '\0':
return "\\0";
case '\a':
return "\\a";
case '\b':
return "\\b";
case '\f':
return "\\f";
case '\n':
return "\\n";
case '\r':
return "\\r";
case '\t':
return "\\t";
case '\v':
return "\\v";
default:
if (char.IsControl(ch) || char.IsSurrogate(ch) ||
// print all uncommon white spaces as numbers
(char.IsWhiteSpace(ch) && ch != ' ')) {
return "\\u" + ((int)ch).ToString("x4");
} else {
return ch.ToString();
}
}
}
/// <summary>
/// Converts special characters to escape sequences within the given string.
/// </summary>
public static string ConvertString(string str)
{
StringBuilder sb = new StringBuilder ();
foreach (char ch in str) {
if (ch == '"') {
sb.Append("\\\"");
} else {
sb.Append(ConvertChar(ch));
}
}
return sb.ToString();
}
public override void WritePrimitiveType(string type)
{
textWriter.Write(type);
column += type.Length;
if (type == "new") {
textWriter.Write("()");
column += 2;
}
}
public override void StartNode(AstNode node)
{
// Write out the indentation, so that overrides of this method
// can rely use the current output length to identify the position of the node
@ -228,7 +399,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -228,7 +399,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteIndentation();
}
public virtual void EndNode(AstNode node)
public override void EndNode(AstNode node)
{
}
}

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs

@ -436,18 +436,26 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -436,18 +436,26 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return 0;
}
sealed class SegmentTrackingOutputFormatter : TextWriterOutputFormatter
sealed class SegmentTrackingTokenWriter : TextWriterTokenWriter
{
internal List<KeyValuePair<AstNode, Segment>> NewSegments = new List<KeyValuePair<AstNode, Segment>>();
readonly Stack<int> startOffsets = new Stack<int>();
readonly StringWriter stringWriter;
public SegmentTrackingOutputFormatter (StringWriter stringWriter)
public SegmentTrackingTokenWriter(StringWriter stringWriter)
: base(stringWriter)
{
this.stringWriter = stringWriter;
}
public override void WriteIdentifier (Identifier identifier)
{
int startOffset = stringWriter.GetStringBuilder ().Length;
int endOffset = startOffset + (identifier.Name ?? "").Length + (identifier.IsVerbatim ? 1 : 0);
NewSegments.Add(new KeyValuePair<AstNode, Segment>(identifier, new Segment(startOffset, endOffset)));
base.WriteIdentifier (identifier);
}
public override void StartNode (AstNode node)
{
base.StartNode (node);
@ -466,7 +474,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -466,7 +474,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
protected NodeOutput OutputNode(int indentLevel, AstNode node, bool startWithNewLine = false)
{
var stringWriter = new StringWriter ();
var formatter = new SegmentTrackingOutputFormatter (stringWriter);
var formatter = new SegmentTrackingTokenWriter(stringWriter);
formatter.Indentation = indentLevel;
formatter.IndentationString = Options.TabsToSpaces ? new string (' ', Options.IndentSize) : "\t";
stringWriter.NewLine = Options.EolMarker;

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpUnresolvedFile.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
/// Represents a file that was parsed and converted for the type system.
/// </summary>
[Serializable, FastSerializerVersion(TypeSystemConvertVisitor.version)]
public sealed class CSharpUnresolvedFile : AbstractFreezable, IUnresolvedFile, IUnresolvedDocumentationProvider
public class CSharpUnresolvedFile : AbstractFreezable, IUnresolvedFile, IUnresolvedDocumentationProvider
{
// The 'FastSerializerVersion' attribute on CSharpUnresolvedFile must be incremented when fixing
// bugs in the TypeSystemConvertVisitor

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.ConsistencyCheck/Xml/XmlReaderTest.cs

@ -92,9 +92,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck.Xml @@ -92,9 +92,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck.Xml
if (val == null)
return "null";
else if (val is string)
return "\"" + CSharpOutputVisitor.ConvertString((string)val) + "\"";
return "\"" + TextWriterTokenWriter.ConvertString((string)val) + "\"";
else if (val is char)
return "'" + CSharpOutputVisitor.ConvertChar((char)val) + "'";
return "'" + TextWriterTokenWriter.ConvertChar((char)val) + "'";
else
return val.ToString();
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp
policy = FormattingOptionsFactory.CreateMono();
StringWriter w = new StringWriter();
w.NewLine = "\n";
node.AcceptVisitor(new CSharpOutputVisitor(new TextWriterOutputFormatter(w) { IndentationString = "$" }, policy));
node.AcceptVisitor(new CSharpOutputVisitor(new TextWriterTokenWriter(w) { IndentationString = "$" }, policy));
Assert.AreEqual(expected.Replace("\r", ""), w.ToString());
}

87
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertMissingTokensDecoratorTests.cs

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Editor;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Parser;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Description of InsertMissingTokensDecoratorTests.
/// </summary>
[TestFixture]
public class InsertMissingTokensDecoratorTests
{
string[] fileNames;
[TestFixtureSetUp]
public void SetUp()
{
string path = Path.GetFullPath (Path.Combine ("..", ".."));
if (!File.Exists(Path.Combine(path, "NRefactory.sln")))
throw new InvalidOperationException("Test cannot find the NRefactory source code in " + path);
fileNames = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories);
}
static void RemoveTokens(AstNode node)
{
foreach (var child in node.Descendants) {
if (child is CSharpTokenNode && !(child is CSharpModifierToken))
child.Remove();
else if (child.NodeType == NodeType.Whitespace)
child.Remove();
}
}
void AssertOutput(AstNode node)
{
RemoveTokens(node);
StringWriter w = new StringWriter();
w.NewLine = "\n";
node.AcceptVisitor(new CSharpOutputVisitor(TokenWriter.CreateWriterThatSetsLocationsInAST(w), FormattingOptionsFactory.CreateSharpDevelop()));
var doc = new ReadOnlyDocument(w.ToString());
ConsistencyChecker.CheckMissingTokens(node, "test.cs", doc);
ConsistencyChecker.CheckPositionConsistency(node, "test.cs", doc);
}
[Test]
public void SimpleClass()
{
var code = @"class Test
{
}
";
var unit = SyntaxTree.Parse(code);
AssertOutput(unit);
}
[Test]
public void SimpleMethod()
{
var code = @"class Test
{
void A ()
{
}
}
";
var unit = SyntaxTree.Parse(code);
AssertOutput(unit);
}
[Test, Ignore]
public void SelfTest()
{
foreach (var file in fileNames) {
Console.WriteLine("processing {0}...", file);
var node = SyntaxTree.Parse(File.ReadAllText(file), file);
AssertOutput(node);
}
}
}
}

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs

@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp
expr.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
StringWriter w = new StringWriter();
w.NewLine = " ";
expr.AcceptVisitor(new CSharpOutputVisitor(new TextWriterOutputFormatter(w) { IndentationString = "" }, policy));
expr.AcceptVisitor(new CSharpOutputVisitor(new TextWriterTokenWriter(w) { IndentationString = "" }, policy));
return w.ToString();
}
@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp
expr.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = false });
StringWriter w = new StringWriter();
w.NewLine = " ";
expr.AcceptVisitor(new CSharpOutputVisitor(new TextWriterOutputFormatter(w) { IndentationString = "" }, policy));
expr.AcceptVisitor(new CSharpOutputVisitor(new TextWriterTokenWriter(w) { IndentationString = "" }, policy));
return w.ToString();
}

101
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ConsistencyChecker.cs

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using ICSharpCode.NRefactory.Editor;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser
{
/// <summary>
/// Provides utilities to check whether positions and/or tokens in an AST are valid.
/// </summary>
public static class ConsistencyChecker
{
static void PrintNode (AstNode node)
{
Console.WriteLine ("Parent:" + node.GetType ());
Console.WriteLine ("Children:");
foreach (var c in node.Children)
Console.WriteLine (c.GetType () +" at:"+ c.StartLocation +"-"+ c.EndLocation + " Role: "+ c.Role);
Console.WriteLine ("----");
}
public static void CheckPositionConsistency (AstNode node, string currentFileName, IDocument currentDocument = null)
{
if (currentDocument == null)
currentDocument = new ReadOnlyDocument(File.ReadAllText(currentFileName));
string comment = "(" + node.GetType ().Name + " at " + node.StartLocation + " in " + currentFileName + ")";
var pred = node.StartLocation <= node.EndLocation;
if (!pred)
PrintNode (node);
Assert.IsTrue(pred, "StartLocation must be before EndLocation " + comment);
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
bool assertion = child.StartLocation >= prevNodeEnd;
if (!assertion) {
PrintNode (prevNode);
PrintNode (node);
}
Assert.IsTrue(assertion, currentFileName + ": Child " + child.GetType () +" (" + child.StartLocation + ")" +" must start after previous sibling " + prevNode.GetType () + "(" + prevNode.StartLocation + ")");
CheckPositionConsistency(child, currentFileName, currentDocument);
prevNodeEnd = child.EndLocation;
prevNode = child;
}
Assert.IsTrue(prevNodeEnd <= node.EndLocation, "Last child must end before parent node ends " + comment);
}
public static void CheckMissingTokens(AstNode node, string currentFileName, IDocument currentDocument = null)
{
if (currentDocument == null)
currentDocument = new ReadOnlyDocument(File.ReadAllText(currentFileName));
if (IsLeafNode(node)) {
Assert.IsNull(node.FirstChild, "Token nodes should not have children");
} else {
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
CheckWhitespace(prevNode, prevNodeEnd, child, child.StartLocation, currentFileName, currentDocument);
CheckMissingTokens(child, currentFileName, currentDocument);
prevNode = child;
prevNodeEnd = child.EndLocation;
}
CheckWhitespace(prevNode, prevNodeEnd, node, node.EndLocation, currentFileName, currentDocument);
}
}
static bool IsLeafNode(AstNode node)
{
if (node.NodeType == NodeType.Token)
return true;
if (node.NodeType == NodeType.Whitespace)
return !(node is PragmaWarningPreprocessorDirective);
return node is PrimitiveType || node is PrimitiveExpression || node is NullReferenceExpression;
}
static void CheckWhitespace(AstNode startNode, TextLocation whitespaceStart, AstNode endNode, TextLocation whitespaceEnd, string currentFileName, IDocument currentDocument)
{
if (whitespaceStart == whitespaceEnd || startNode == endNode)
return;
Assert.Greater(whitespaceStart.Line, 0);
Assert.Greater(whitespaceStart.Column, 0);
Assert.Greater(whitespaceEnd.Line, 0);
Assert.Greater(whitespaceEnd.Column, 0);
Assert.IsTrue(whitespaceEnd >= whitespaceStart, endNode.GetType().Name + ".StartLocation < " + startNode.GetType().Name + ".EndLocation: " + whitespaceEnd + " < " + whitespaceStart);
int start = currentDocument.GetOffset(whitespaceStart.Line, whitespaceStart.Column);
int end = currentDocument.GetOffset(whitespaceEnd.Line, whitespaceEnd.Column);
string text = currentDocument.GetText(start, end - start);
bool assertion = string.IsNullOrWhiteSpace(text);
if (!assertion) {
if (startNode.Parent != endNode.Parent)
PrintNode (startNode.Parent);
PrintNode (endNode.Parent);
}
Assert.IsTrue(assertion, "Expected whitespace between " + startNode.GetType () +":" + whitespaceStart + " and " + endNode.GetType () + ":" + whitespaceEnd
+ ", but got '" + text + "' (in " + currentFileName + " parent:" + startNode.Parent.GetType () +")");
}
}
}

84
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseSelfTests.cs

@ -67,99 +67,21 @@ namespace ICSharpCode.NRefactory.CSharp.Parser @@ -67,99 +67,21 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
}
#region ParseAndCheckPositions
string currentFileName;
ReadOnlyDocument currentDocument;
[Test, Ignore("Positions still are incorrect in several cases")]
public void ParseAndCheckPositions()
{
CSharpParser parser = new CSharpParser();
foreach (string fileName in fileNames) {
this.currentDocument = new ReadOnlyDocument(File.ReadAllText(fileName));
var currentDocument = new ReadOnlyDocument(File.ReadAllText(fileName));
SyntaxTree syntaxTree = parser.Parse(currentDocument, fileName);
if (parser.HasErrors)
continue;
this.currentFileName = fileName;
CheckPositionConsistency(syntaxTree);
CheckMissingTokens(syntaxTree);
ConsistencyChecker.CheckPositionConsistency(syntaxTree, fileName, currentDocument);
ConsistencyChecker.CheckMissingTokens(syntaxTree, fileName, currentDocument);
}
}
void PrintNode (AstNode node)
{
Console.WriteLine ("Parent:" + node.GetType ());
Console.WriteLine ("Children:");
foreach (var c in node.Children)
Console.WriteLine (c.GetType () +" at:"+ c.StartLocation +"-"+ c.EndLocation + " Role: "+ c.Role);
Console.WriteLine ("----");
}
void CheckPositionConsistency (AstNode node)
{
string comment = "(" + node.GetType ().Name + " at " + node.StartLocation + " in " + currentFileName + ")";
var pred = node.StartLocation <= node.EndLocation;
if (!pred)
PrintNode (node);
Assert.IsTrue(pred, "StartLocation must be before EndLocation " + comment);
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
bool assertion = child.StartLocation >= prevNodeEnd;
if (!assertion) {
PrintNode (prevNode);
PrintNode (node);
}
Assert.IsTrue(assertion, currentFileName + ": Child " + child.GetType () +" (" + child.StartLocation + ")" +" must start after previous sibling " + prevNode.GetType () + "(" + prevNode.StartLocation + ")");
CheckPositionConsistency(child);
prevNodeEnd = child.EndLocation;
prevNode = child;
}
Assert.IsTrue(prevNodeEnd <= node.EndLocation, "Last child must end before parent node ends " + comment);
}
void CheckMissingTokens(AstNode node)
{
if (IsLeafNode(node)) {
Assert.IsNull(node.FirstChild, "Token nodes should not have children");
} else {
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
CheckWhitespace(prevNode, prevNodeEnd, child, child.StartLocation);
CheckMissingTokens(child);
prevNode = child;
prevNodeEnd = child.EndLocation;
}
CheckWhitespace(prevNode, prevNodeEnd, node, node.EndLocation);
}
}
bool IsLeafNode(AstNode node)
{
if (node.NodeType == NodeType.Token)
return true;
if (node.NodeType == NodeType.Whitespace)
return !(node is PragmaWarningPreprocessorDirective);
return node is PrimitiveType || node is PrimitiveExpression || node is NullReferenceExpression;
}
void CheckWhitespace(AstNode startNode, TextLocation whitespaceStart, AstNode endNode, TextLocation whitespaceEnd)
{
if (whitespaceStart == whitespaceEnd)
return;
int start = currentDocument.GetOffset(whitespaceStart.Line, whitespaceStart.Column);
int end = currentDocument.GetOffset(whitespaceEnd.Line, whitespaceEnd.Column);
string text = currentDocument.GetText(start, end - start);
bool assertion = string.IsNullOrWhiteSpace(text);
if (!assertion) {
if (startNode.Parent != endNode.Parent)
PrintNode (startNode.Parent);
PrintNode (endNode.Parent);
}
Assert.IsTrue(assertion, "Expected whitespace between " + startNode.GetType () +":" + whitespaceStart + " and " + endNode.GetType () + ":" + whitespaceEnd
+ ", but got '" + text + "' (in " + currentFileName + " parent:" + startNode.Parent.GetType () +")");
}
#endregion
}
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -157,8 +157,10 @@ @@ -157,8 +157,10 @@
<Compile Include="CSharp\CSharpAmbienceTests.cs" />
<Compile Include="CSharp\CodeDomConvertVisitorTests.cs" />
<Compile Include="CSharp\DepthFirstVisitorTests.cs" />
<Compile Include="CSharp\InsertMissingTokensDecoratorTests.cs" />
<Compile Include="CSharp\InsertParenthesesVisitorTests.cs" />
<Compile Include="CSharp\CSharpOutputVisitorTests.cs" />
<Compile Include="CSharp\Parser\ConsistencyChecker.cs" />
<Compile Include="CSharp\Parser\Expression\AnonymousTypeCreateExpressionTests.cs" />
<Compile Include="CSharp\Parser\Expression\ObjectCreateExpressionTests.cs" />
<Compile Include="CSharp\Parser\Expression\UndocumentedExpressionTests.cs" />

21
src/Main/Base/Project/Dom/ClassBrowser/ClassBrowserTreeView.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Windows.Controls;
using ICSharpCode.Core;
using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
@ -11,14 +12,21 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -11,14 +12,21 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
public class ClassBrowserTreeView : SharpTreeView, IClassBrowserTreeView
{
#region IClassBrowser implementation
WorkspaceModel workspace;
public ICollection<IAssemblyList> AssemblyLists {
get { return ((WorkspaceTreeNode)Root).AssemblyLists; }
get { return workspace.AssemblyLists; }
}
public IAssemblyList MainAssemblyList {
get { return ((WorkspaceTreeNode)Root).AssemblyList; }
set { ((WorkspaceTreeNode)Root).AssemblyList = value; }
get { return workspace.MainAssemblyList; }
set { workspace.MainAssemblyList = value; }
}
public IAssemblyModel FindAssemblyModel(FileName fileName)
{
return workspace.FindAssemblyModel(fileName);
}
#endregion
@ -26,12 +34,13 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -26,12 +34,13 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
public ClassBrowserTreeView()
{
WorkspaceTreeNode root = new WorkspaceTreeNode();
this.workspace = root.Workspace;
ClassBrowserTreeView instance = this;
root.AssemblyLists.CollectionChanged += delegate {
instance.ShowRoot = root.AssemblyLists.Count > 0;
root.Workspace.AssemblyLists.CollectionChanged += delegate {
instance.ShowRoot = root.Workspace.AssemblyLists.Count > 0;
};
root.PropertyChanged += delegate {
instance.ShowRoot = root.AssemblyLists.Count > 0;
instance.ShowRoot = root.Workspace.AssemblyLists.Count > 0;
};
this.Root = root;
}

8
src/Main/Base/Project/Dom/ClassBrowser/IClassBrowser.cs

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
using ICSharpCode.TreeView;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
@ -11,10 +11,6 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -11,10 +11,6 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
IAssemblyList MainAssemblyList { get; set; }
ICollection<IAssemblyList> AssemblyLists { get; }
/*
IAssemblyList MainAssemblyList { get; set; }
ICollection<IAssemblyList> AssemblyLists { get; }
*/
IAssemblyModel FindAssemblyModel(FileName fileName);
}
}

5
src/Main/Base/Project/Dom/ClassBrowser/MemberTreeNode.cs

@ -28,10 +28,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -28,10 +28,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
}
public override object Icon {
// TODO why do I have to resolve this?
get {
return ClassBrowserIconService.GetIcon(model.Resolve()).ImageSource;
}
get { return ClassBrowserIconService.GetIcon(model.UnresolvedMember).ImageSource; }
}
object cachedText;

18
src/Main/Base/Project/Dom/ClassBrowser/WorkspaceModel.cs

@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using ICSharpCode.Core;
using ICSharpCode.TreeView;
namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
@ -21,7 +24,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -21,7 +24,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null) {
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
@ -35,10 +38,21 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -35,10 +38,21 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
set {
if (mainAssemblyList != value) {
mainAssemblyList = value;
OnPropertyChanged("AssemblyList");
OnPropertyChanged();
}
}
}
public IAssemblyModel FindAssemblyModel(FileName fileName)
{
foreach (var list in assemblyLists) {
var model = list.Assemblies.FirstOrDefault(m => m.Location == fileName);
if (model != null)
return model;
}
return mainAssemblyList.Assemblies.FirstOrDefault(m => m.Location == fileName);
}
public WorkspaceModel()
{
this.assemblyLists = new SimpleModelCollection<IAssemblyList>();

13
src/Main/Base/Project/Dom/ClassBrowser/WorkspaceTreeNode.cs

@ -36,16 +36,11 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -36,16 +36,11 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
}
WorkspaceModel workspace;
protected static readonly IComparer<SharpTreeNode> ChildNodeComparer = new WorkspaceChildComparer();
public IMutableModelCollection<IAssemblyList> AssemblyLists {
get { return workspace.AssemblyLists; }
public WorkspaceModel Workspace {
get { return workspace; }
}
public IAssemblyList AssemblyList {
get { return workspace.MainAssemblyList; }
set { workspace.MainAssemblyList = value; }
}
protected static readonly IComparer<SharpTreeNode> ChildNodeComparer = new WorkspaceChildComparer();
public WorkspaceTreeNode()
{
@ -68,7 +63,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -68,7 +63,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
public override object Text {
get {
return String.Format(SD.ResourceService.GetString("MainWindow.Windows.ClassBrowser.Workspace"), AssemblyList.Name);
return String.Format(SD.ResourceService.GetString("MainWindow.Windows.ClassBrowser.Workspace"), Workspace.MainAssemblyList.Name);
}
}

16
src/Main/Base/Project/Dom/IAssemblyModel.cs

@ -5,7 +5,9 @@ using System; @@ -5,7 +5,9 @@ using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Parser;
namespace ICSharpCode.SharpDevelop.Dom
{
@ -53,6 +55,11 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -53,6 +55,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// Returns the location of the assembly represented by this model.
/// </summary>
FileName Location { get; }
/// <summary>
/// Returns the assembly references.
/// </summary>
IReadOnlyList<DomAssemblyName> References { get; }
}
/// <summary>
@ -78,6 +85,11 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -78,6 +85,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// Gets the assembly name (short name).
/// </summary>
new string AssemblyName { get; set; }
/// <summary>
/// Returns the assembly references.
/// </summary>
new IReadOnlyList<DomAssemblyName> References { get; set; }
}
public sealed class EmptyAssemblyModel : IAssemblyModel
@ -115,6 +127,10 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -115,6 +127,10 @@ namespace ICSharpCode.SharpDevelop.Dom
return null;
}
}
public IReadOnlyList<DomAssemblyName> References {
get { return EmptyList<DomAssemblyName>.Instance; }
}
}
}

30
src/Main/Base/Project/Dom/IEntityModelContext.cs

@ -91,20 +91,40 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -91,20 +91,40 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
public class DomAssemblyNameReference : IAssemblyReference
{
DomAssemblyName name;
IAssemblySearcher searcher;
public DomAssemblyNameReference(DomAssemblyName name, IAssemblySearcher searcher)
{
if (name == null)
throw new ArgumentNullException("name");
if (searcher == null)
throw new ArgumentNullException("searcher");
this.name = name;
this.searcher = searcher;
}
public IAssembly Resolve(ITypeResolveContext context)
{
return SD.AssemblyParserService.GetAssembly(searcher.FindAssembly(name), true).Resolve(context);
}
}
public class AssemblyEntityModelContext : IEntityModelContext
{
ICompilation compilation;
Lazy<ICompilation> compilation;
IUnresolvedAssembly mainAssembly;
IAssemblyReference[] references;
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, params IAssemblyReference[] references)
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, IAssemblyReference[] references)
{
if (mainAssembly == null)
throw new ArgumentNullException("mainAssembly");
this.mainAssembly = mainAssembly;
this.references = references;
// implement lazy init + weak caching
this.compilation = new SimpleCompilation(mainAssembly, references);
this.compilation = new Lazy<ICompilation>(() => new SimpleCompilation(mainAssembly, references));
}
public string AssemblyName {
@ -117,7 +137,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -117,7 +137,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public ICompilation GetCompilation()
{
return compilation;
return compilation.Value;
}
public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2)

5
src/Main/Base/Project/Dom/IMemberModel.cs

@ -24,6 +24,11 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -24,6 +24,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </summary>
new IMember Resolve(ICompilation compilation);
/// <summary>
/// Gets the unresolved member.
/// </summary>
IUnresolvedMember UnresolvedMember { get; }
/// <summary>
/// Gets if the member is virtual. Is true only if the "virtual" modifier was used, but non-virtual
/// members can be overridden, too; if they are abstract or overriding a method.

2
src/Main/Base/Project/Dom/IModelFactory.cs

@ -15,6 +15,6 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -15,6 +15,6 @@ namespace ICSharpCode.SharpDevelop.Dom
{
ITypeDefinitionModel CreateTypeDefinitionModel(IEntityModelContext context, params IUnresolvedTypeDefinition[] parts);
IMemberModel CreateMemberModel(IEntityModelContext context, IUnresolvedMember member);
IAssemblyModel CreateAssemblyModel(IEntityModelContext context);
IUpdateableAssemblyModel CreateAssemblyModel(IEntityModelContext context);
}
}

59
src/Main/Base/Project/Dom/ModelFactoryExtensions.cs

@ -1,59 +0,0 @@ @@ -1,59 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Linq;
using System.IO;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.SharpDevelop.Dom
{
public static class ModelFactoryExtensions
{
/// <summary>
/// Creates an <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> from a file name.
/// </summary>
/// <param name="modelFactory">Model factory.</param>
/// <param name="fileName">Assembly file name.</param>
/// <returns>Created <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/>.</returns>
public static IAssemblyModel CreateAssemblyModelFromFile(this IModelFactory modelFactory, string fileName)
{
var loader = new CecilLoader();
loader.IncludeInternalMembers = true;
loader.LazyLoad = true;
var assembly = loader.LoadAssemblyFile(fileName);
IEntityModelContext context = new AssemblyEntityModelContext(assembly);
IAssemblyModel model = modelFactory.CreateAssemblyModel(context);
if (model is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)model).Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.TopLevelTypeDefinitions.ToList());
((IUpdateableAssemblyModel) model).AssemblyName = assembly.AssemblyName;
}
return model;
}
/// <summary>
/// Creates an <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> from a file name and catches
/// errors by showing messages to user.
/// </summary>
/// <param name="modelFactory">Model factory.</param>
/// <param name="fileName">Assembly file name.</param>
/// <returns>
/// Created <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> or <b>null</b>,
/// if model couldn't be created.
/// </returns>
public static IAssemblyModel SafelyCreateAssemblyModelFromFile(this IModelFactory modelFactory, string fileName)
{
try {
return modelFactory.CreateAssemblyModelFromFile(fileName);
} catch (BadImageFormatException) {
SD.MessageService.ShowWarningFormatted("${res:ICSharpCode.SharpDevelop.Dom.AssemblyInvalid}", Path.GetFileName(fileName));
} catch (FileNotFoundException) {
SD.MessageService.ShowWarningFormatted("${res:ICSharpCode.SharpDevelop.Dom.AssemblyNotAccessible}", fileName);
}
return null;
}
}
}

2
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -118,7 +118,6 @@ @@ -118,7 +118,6 @@
<Compile Include="Dom\ModelCollectionLinq.cs" />
<Compile Include="Dom\ImmutableModelCollection.cs" />
<Compile Include="Dom\ModelCollectionTreeNode.cs" />
<Compile Include="Dom\ModelFactoryExtensions.cs" />
<Compile Include="Dom\SimpleModelCollection.cs" />
<Compile Include="Dom\SynchronizedModelCollection.cs" />
<Compile Include="Editor\AvalonEditTextEditorAdapter.cs" />
@ -160,6 +159,7 @@ @@ -160,6 +159,7 @@
<DependentUpon>ToolTipService.cs</DependentUpon>
</Compile>
<Compile Include="Editor\ToolTipService.cs" />
<Compile Include="Parser\DefaultAssemblySearcher.cs" />
<Compile Include="Parser\DomAssemblyName.cs" />
<Compile Include="Parser\IAssemblyParserService.cs" />
<Compile Include="Parser\IGlobalAssemblyCacheService.cs" />

58
src/Main/Base/Project/Parser/DefaultAssemblySearcher.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
namespace ICSharpCode.SharpDevelop.Parser
{
public class DefaultAssemblySearcher : IAssemblySearcher
{
FileName mainAssemblyFileName;
DirectoryName baseDirectory;
public DefaultAssemblySearcher(FileName mainAssemblyFileName)
{
if (mainAssemblyFileName == null)
throw new ArgumentNullException("mainAssemblyFileName");
this.mainAssemblyFileName = mainAssemblyFileName;
this.baseDirectory = mainAssemblyFileName.GetParentDirectory();
}
public FileName FindAssembly(DomAssemblyName fullName)
{
// look for the assembly in the current loaded assembly lists
var classBrowser = SD.GetRequiredService<IClassBrowser>();
var relevantClassBrowserAssemblies = classBrowser.AssemblyLists
.Where(l => l.Assemblies.Any(a => a.Location == mainAssemblyFileName))
.SelectMany(l => l.Assemblies);
foreach (var asm in relevantClassBrowserAssemblies) {
// TODO I am pretty sure we need the full name here as well...
if (asm.AssemblyName == fullName.ShortName)
return asm.Location;
}
// look in GAC
var gacFileName = SD.GlobalAssemblyCache.FindAssemblyInNetGac(fullName);
if (gacFileName != null)
return gacFileName;
// scan current directory
var fileName = baseDirectory.CombineFile(fullName.ShortName + ".dll");
if (File.Exists(fileName))
return fileName;
fileName = baseDirectory.CombineFile(fullName.ShortName + ".exe");
if (File.Exists(fileName))
return fileName;
return null;
}
}
}

34
src/Main/Base/Project/Parser/IAssemblyParserService.cs

@ -2,11 +2,16 @@ @@ -2,11 +2,16 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
namespace ICSharpCode.SharpDevelop.Parser
{
@ -19,12 +24,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -19,12 +24,7 @@ namespace ICSharpCode.SharpDevelop.Parser
/// <summary>
/// Loads the specified assembly file from disk.
/// </summary>
IUnresolvedAssembly GetAssembly(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Loads the specified assembly file from disk.
/// </summary>
Task<IUnresolvedAssembly> GetAssemblyAsync(FileName fileName, CancellationToken cancellationToken = default(CancellationToken));
IUnresolvedAssembly GetAssembly(FileName fileName, bool includeInternalMembers = false, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// <code>using (AssemblyParserService.AvoidRedundantChecks())</code>
@ -50,6 +50,28 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -50,6 +50,28 @@ namespace ICSharpCode.SharpDevelop.Parser
void RefreshAssembly(FileName fileName);
event EventHandler<RefreshAssemblyEventArgs> AssemblyRefreshed;
/// <summary>
/// Creates an IAssemblyModel for the given assembly file.
/// </summary>
IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false);
/// <summary>
/// Creates an <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> from a file name and catches
/// errors by showing messages to user.
/// </summary>
/// <param name="modelFactory">Model factory.</param>
/// <param name="fileName">Assembly file name.</param>
/// <returns>
/// Created <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> or <b>null</b>,
/// if model couldn't be created.
/// </returns>
IAssemblyModel GetAssemblyModelSafe(FileName fileName, bool includeInternalMembers = false);
}
public interface IAssemblySearcher
{
FileName FindAssembly(DomAssemblyName fullName);
}
public class RefreshAssemblyEventArgs : EventArgs

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

@ -440,7 +440,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -440,7 +440,7 @@ namespace ICSharpCode.SharpDevelop.Parser
foreach (var file in assemblyFiles) {
progressMonitor.CancellationToken.ThrowIfCancellationRequested();
if (File.Exists(file)) {
var pc = SD.AssemblyParserService.GetAssembly(file, progressMonitor.CancellationToken);
var pc = SD.AssemblyParserService.GetAssembly(file, false, progressMonitor.CancellationToken);
if (pc != null) {
newReferences.Add(pc);
}

15
src/Main/Base/Project/Src/Project/CompilableProject.cs

@ -359,6 +359,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -359,6 +359,8 @@ namespace ICSharpCode.SharpDevelop.Project
var pc = ProjectContent;
if (pc != null && assemblyModel is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)assemblyModel).AssemblyName = AssemblyName;
((IUpdateableAssemblyModel)assemblyModel).References = pc.AssemblyReferences
.Select(ResolveReference).Where(r => r != null).ToList();
// Add the already loaded files into the model
foreach (var file in pc.Files) {
((IUpdateableAssemblyModel)assemblyModel).Update(null, file);
@ -369,6 +371,18 @@ namespace ICSharpCode.SharpDevelop.Project @@ -369,6 +371,18 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
DomAssemblyName ResolveReference(IAssemblyReference reference)
{
if (reference is IUnresolvedAssembly)
return new DomAssemblyName(((IUnresolvedAssembly)reference).FullAssemblyName);
if (reference is ProjectReferenceProjectItem) {
var project = ((ProjectReferenceProjectItem)reference).ReferencedProject;
if (project == null) return null;
return new DomAssemblyName(project.ProjectContent.FullAssemblyName);
}
return null;
}
public override void OnParseInformationUpdated(ParseInformationEventArgs args)
{
var c = projectContentContainer;
@ -379,6 +393,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -379,6 +393,7 @@ namespace ICSharpCode.SharpDevelop.Project
SD.MainThread.InvokeAsyncAndForget(delegate {
if (assemblyModel is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)assemblyModel).Update(args.OldUnresolvedFile, args.NewUnresolvedFile);
// TODO : update references as well?
}
ParseInformationUpdated(null, args);
});

33
src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs

@ -432,29 +432,10 @@ namespace ICSharpCode.SharpDevelop @@ -432,29 +432,10 @@ namespace ICSharpCode.SharpDevelop
return true;
}
return false;
} else {
return FileService.JumpToFilePosition(region.FileName, region.BeginLine, region.BeginColumn) != null;
}
}
#endregion
#region Navigate to Member
/* Part of Eusebiu's debugger/decompiler implementation
public static bool NavigateTo(string assemblyFile, string typeName, string entityTag, int lineNumber = 0, bool updateMarker = true)
{
if (string.IsNullOrEmpty(assemblyFile))
throw new ArgumentException("assemblyFile is null or empty");
if (string.IsNullOrEmpty(typeName))
throw new ArgumentException("typeName is null or empty");
foreach (var item in AddInTree.BuildItems<INavigateToMemberService>("/SharpDevelop/Services/NavigateToEntityService", null, false)) {
if (item.NavigateToMember(assemblyFile, typeName, entityTag, lineNumber, updateMarker))
return true;
}
return false;
return FileService.JumpToFilePosition(region.FileName, region.BeginLine, region.BeginColumn) != null;
}
*/
#endregion
}
@ -468,16 +449,4 @@ namespace ICSharpCode.SharpDevelop @@ -468,16 +449,4 @@ namespace ICSharpCode.SharpDevelop
{
bool NavigateToEntity(IEntity entity);
}
/* Part of Eusebiu's debugger/decompiler implementation
/// <summary>
/// Called by <see cref="NavigationService.NavigateTo"/> when the member reference is not defined in source code.
/// </summary>
/// <remarks>
/// Loaded from addin tree path "/SharpDevelop/Services/NavigateToEntityService"
/// </remarks>
public interface INavigateToMemberService
{
bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber, bool updateMarker);
}
*/
}

7
src/Main/SharpDevelop/Dom/AssemblyModel.cs

@ -19,12 +19,14 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -19,12 +19,14 @@ namespace ICSharpCode.SharpDevelop.Dom
TopLevelTypeDefinitionModelCollection typeDeclarations;
KeyedModelCollection<string, NamespaceModel> namespaces;
NamespaceModel rootNamespace;
IReadOnlyList<DomAssemblyName> references;
public AssemblyModel(IEntityModelContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
this.references = EmptyList<DomAssemblyName>.Instance;
this.rootNamespace = new NamespaceModel(context.Project, null, "");
this.typeDeclarations = new TopLevelTypeDefinitionModelCollection(context);
this.typeDeclarations.CollectionChanged += TypeDeclarationsCollectionChanged;
@ -139,5 +141,10 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -139,5 +141,10 @@ namespace ICSharpCode.SharpDevelop.Dom
d.Dispose();
}
}
public IReadOnlyList<DomAssemblyName> References {
get { return references; }
set { references = value; }
}
}
}

15
src/Main/SharpDevelop/Dom/ClassBrowser/ClassBrowserPad.cs

@ -12,6 +12,7 @@ using ICSharpCode.Core.Presentation; @@ -12,6 +12,7 @@ using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.TreeView;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Workbench;
@ -87,6 +88,11 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -87,6 +88,11 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
set { treeView.MainAssemblyList = value; }
}
public IAssemblyModel FindAssemblyModel(FileName fileName)
{
return treeView.FindAssemblyModel(fileName);
}
#endregion
const string PersistedWorkspaceSetting = "ClassBrowser.Workspaces";
@ -224,14 +230,13 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -224,14 +230,13 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
{
var modelFactory = SD.GetRequiredService<IModelFactory>();
try {
return modelFactory.CreateAssemblyModelFromFile(fileName);
return SD.AssemblyParserService.GetAssemblyModel(new FileName(fileName), true);
} catch (Exception) {
// Special AssemblyModel for unresolved file references
IEntityModelContext unresolvedContext = new UnresolvedAssemblyEntityModelContext(Path.GetFileName(fileName), fileName);
IAssemblyModel unresolvedModel = modelFactory.CreateAssemblyModel(unresolvedContext);
if (unresolvedModel is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel) unresolvedModel).AssemblyName = unresolvedContext.AssemblyName;
}
IUpdateableAssemblyModel unresolvedModel = modelFactory.CreateAssemblyModel(unresolvedContext);
unresolvedModel.AssemblyName = unresolvedContext.AssemblyName;
unresolvedModel.References = EmptyList<DomAssemblyName>.Instance;
return unresolvedModel;
}

7
src/Main/SharpDevelop/Dom/ClassBrowser/Commands.cs

@ -24,9 +24,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -24,9 +24,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
openFileDialog.Filter = "Assembly files (*.exe, *.dll)|*.exe;*.dll";
openFileDialog.CheckFileExists = true;
openFileDialog.CheckPathExists = true;
if (openFileDialog.ShowDialog() ?? false)
{
IAssemblyModel assemblyModel = modelFactory.SafelyCreateAssemblyModelFromFile(openFileDialog.FileName);
if (openFileDialog.ShowDialog() ?? false) {
IAssemblyModel assemblyModel = SD.AssemblyParserService.GetAssemblyModelSafe(new ICSharpCode.Core.FileName(openFileDialog.FileName), true);
if (assemblyModel != null)
classBrowser.MainAssemblyList.Assemblies.Add(assemblyModel);
}
@ -48,7 +47,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -48,7 +47,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
if (gacDialog.ShowDialog() ?? false)
{
foreach (string assemblyFile in gacDialog.SelectedFileNames) {
IAssemblyModel assemblyModel = modelFactory.SafelyCreateAssemblyModelFromFile(assemblyFile);
IAssemblyModel assemblyModel = SD.AssemblyParserService.GetAssemblyModelSafe(new ICSharpCode.Core.FileName(assemblyFile), true);
if (assemblyModel != null)
classBrowser.MainAssemblyList.Assemblies.Add(assemblyModel);
}

2
src/Main/SharpDevelop/Dom/ModelFactory.cs

@ -8,7 +8,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -8,7 +8,7 @@ namespace ICSharpCode.SharpDevelop.Dom
{
sealed class ModelFactory : IModelFactory
{
public IAssemblyModel CreateAssemblyModel(IEntityModelContext context)
public IUpdateableAssemblyModel CreateAssemblyModel(IEntityModelContext context)
{
return new AssemblyModel(context);
}

118
src/Main/SharpDevelop/Parser/AssemblyParserService.cs

@ -5,14 +5,19 @@ using System; @@ -5,14 +5,19 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using Mono.Cecil;
namespace ICSharpCode.SharpDevelop.Parser
@ -23,15 +28,21 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -23,15 +28,21 @@ namespace ICSharpCode.SharpDevelop.Parser
sealed class AssemblyParserService : IAssemblyParserService
{
#region Get Assembly By File Name
[Serializable]
[FastSerializerVersion(1)]
sealed class LoadedAssembly
{
public readonly Task<IUnresolvedAssembly> ProjectContent;
public readonly IUnresolvedAssembly ProjectContent;
public readonly DateTime AssemblyFileLastWriteTime;
public readonly bool HasInternalMembers;
public readonly IReadOnlyList<DomAssemblyName> References;
public LoadedAssembly(Task<IUnresolvedAssembly> projectContent, DateTime assemblyFileLastWriteTime)
public LoadedAssembly(IUnresolvedAssembly projectContent, DateTime assemblyFileLastWriteTime, bool hasInternalMembers, IEnumerable<DomAssemblyName> references)
{
this.ProjectContent = projectContent;
this.AssemblyFileLastWriteTime = assemblyFileLastWriteTime;
this.HasInternalMembers = hasInternalMembers;
this.References = references.ToArray();
}
}
@ -40,26 +51,11 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -40,26 +51,11 @@ namespace ICSharpCode.SharpDevelop.Parser
[ThreadStatic] static Dictionary<FileName, LoadedAssembly> up2dateProjectContents;
public IUnresolvedAssembly GetAssembly(FileName fileName, CancellationToken cancellationToken = default(CancellationToken))
public IUnresolvedAssembly GetAssembly(FileName fileName, bool includeInternalMembers = false, CancellationToken cancellationToken = default(CancellationToken))
{
// We currently do not support cancelling the load operation itself, because another GetAssembly() call
// with a different cancellation token might request the same assembly.
bool isNewTask;
LoadedAssembly asm = GetLoadedAssembly(fileName, out isNewTask);
if (isNewTask)
asm.ProjectContent.RunSynchronously();
else
asm.ProjectContent.Wait(cancellationToken);
return asm.ProjectContent.Result;
}
public Task<IUnresolvedAssembly> GetAssemblyAsync(FileName fileName, CancellationToken cancellationToken = default(CancellationToken))
{
bool isNewTask;
LoadedAssembly asm = GetLoadedAssembly(fileName, out isNewTask);
if (isNewTask)
asm.ProjectContent.Start();
return asm.ProjectContent;
return GetLoadedAssembly(fileName, includeInternalMembers).ProjectContent;
}
/// <summary>
@ -86,19 +82,18 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -86,19 +82,18 @@ namespace ICSharpCode.SharpDevelop.Parser
void CleanWeakDictionary()
{
Debug.Assert(Monitor.IsEntered(projectContentDictionary));
List<FileName> removed = new List<FileName>();
foreach (var pair in projectContentDictionary) {
//if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
}
foreach (var key in removed)
projectContentDictionary.Remove(key);
// Debug.Assert(Monitor.IsEntered(projectContentDictionary));
// List<FileName> removed = new List<FileName>();
// foreach (var pair in projectContentDictionary) {
// if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
// }
// foreach (var key in removed)
// projectContentDictionary.Remove(key);
}
LoadedAssembly GetLoadedAssembly(FileName fileName, out bool isNewTask)
LoadedAssembly GetLoadedAssembly(FileName fileName, bool includeInternalMembers)
{
isNewTask = false;
LoadedAssembly asm;
var up2dateProjectContents = AssemblyParserService.up2dateProjectContents;
if (up2dateProjectContents != null) {
@ -109,15 +104,13 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -109,15 +104,13 @@ namespace ICSharpCode.SharpDevelop.Parser
lock (projectContentDictionary) {
if (projectContentDictionary.TryGetValue(fileName, out asm)) {
if (asm.AssemblyFileLastWriteTime == lastWriteTime) {
return asm;
if (!includeInternalMembers || includeInternalMembers == asm.HasInternalMembers)
return asm;
}
} else {
asm = null;
}
var task = new Task<IUnresolvedAssembly>(() => LoadAssembly(fileName, CancellationToken.None));
isNewTask = true;
asm = new LoadedAssembly(task, lastWriteTime);
asm = LoadAssembly(fileName, CancellationToken.None, includeInternalMembers);
if (up2dateProjectContents == null)
CleanWeakDictionary();
// The assembly might already be in the dictionary if we had loaded it before,
@ -130,13 +123,15 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -130,13 +123,15 @@ namespace ICSharpCode.SharpDevelop.Parser
#endregion
#region Load Assembly
IUnresolvedAssembly LoadAssembly(FileName fileName, CancellationToken cancellationToken)
LoadedAssembly LoadAssembly(FileName fileName, CancellationToken cancellationToken, bool includeInternalMembers)
{
DateTime lastWriteTime = File.GetLastWriteTimeUtc(fileName);
string cacheFileName = GetCacheFileName(fileName);
IUnresolvedAssembly pc = TryReadFromCache(cacheFileName, lastWriteTime);
if (pc != null)
return pc;
LoadedAssembly pc = TryReadFromCache(cacheFileName, lastWriteTime);
if (pc != null) {
if (!includeInternalMembers || includeInternalMembers == pc.HasInternalMembers)
return pc;
}
//LoggingService.Debug("Loading " + fileName);
cancellationToken.ThrowIfCancellationRequested();
@ -145,6 +140,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -145,6 +140,7 @@ namespace ICSharpCode.SharpDevelop.Parser
ModuleDefinition module = ModuleDefinition.ReadModule(fileName, param);
CecilLoader l = new CecilLoader();
l.IncludeInternalMembers = includeInternalMembers;
string xmlDocFile = FindXmlDocumentation(fileName, module.Runtime);
if (xmlDocFile != null) {
try {
@ -158,7 +154,9 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -158,7 +154,9 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
l.CancellationToken = cancellationToken;
pc = l.LoadModule(module);
var references = module.AssemblyReferences
.Select(anr => new DomAssemblyName(anr.FullName));
pc = new LoadedAssembly(l.LoadModule(module), lastWriteTime, includeInternalMembers, references);
SaveToCacheAsync(cacheFileName, lastWriteTime, pc).FireAndForget();
//SaveToCache(cacheFileName, lastWriteTime, pc);
return pc;
@ -241,7 +239,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -241,7 +239,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return cacheFileName;
}
static IUnresolvedAssembly TryReadFromCache(string cacheFileName, DateTime lastWriteTime)
static LoadedAssembly TryReadFromCache(string cacheFileName, DateTime lastWriteTime)
{
if (cacheFileName == null || !File.Exists(cacheFileName))
return null;
@ -254,7 +252,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -254,7 +252,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return null;
}
FastSerializer s = new FastSerializer();
return (IUnresolvedAssembly)s.Deserialize(reader);
return s.Deserialize(reader) as LoadedAssembly;
}
}
} catch (IOException ex) {
@ -269,19 +267,19 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -269,19 +267,19 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc)
Task SaveToCacheAsync(string cacheFileName, DateTime lastWriteTime, LoadedAssembly asm)
{
if (cacheFileName == null)
return Task.FromResult<object>(null);
// Call SaveToCache on a background task:
var shutdownService = SD.ShutdownService;
var task = IOTaskScheduler.Factory.StartNew(delegate { SaveToCache(cacheFileName, lastWriteTime, pc); }, shutdownService.ShutdownToken);
var task = IOTaskScheduler.Factory.StartNew(delegate { SaveToCache(cacheFileName, lastWriteTime, asm); }, shutdownService.ShutdownToken);
shutdownService.AddBackgroundTask(task);
return task;
}
void SaveToCache(string cacheFileName, DateTime lastWriteTime, IUnresolvedAssembly pc)
void SaveToCache(string cacheFileName, DateTime lastWriteTime, LoadedAssembly asm)
{
if (cacheFileName == null)
return;
@ -292,7 +290,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -292,7 +290,7 @@ namespace ICSharpCode.SharpDevelop.Parser
using (BinaryWriter writer = new BinaryWriterWith7BitEncodedInts(fs)) {
writer.Write(lastWriteTime.Ticks);
FastSerializer s = new FastSerializer();
s.Serialize(writer, pc);
s.Serialize(writer, asm);
}
}
} catch (IOException ex) {
@ -318,7 +316,7 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -318,7 +316,7 @@ namespace ICSharpCode.SharpDevelop.Parser
return;
}
}
var oldAssembly = asm.ProjectContent.Result;
var oldAssembly = asm.ProjectContent;
var newAssembly = GetAssembly(fileName);
if (oldAssembly != newAssembly) {
var handler = AssemblyRefreshed;
@ -327,5 +325,33 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -327,5 +325,33 @@ namespace ICSharpCode.SharpDevelop.Parser
}
}
#endregion
public IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false)
{
LoadedAssembly assembly = GetLoadedAssembly(fileName, includeInternalMembers);
IEntityModelContext context = new AssemblyEntityModelContext(
assembly.ProjectContent,
assembly.References.Select(name => new DomAssemblyNameReference(name, new DefaultAssemblySearcher(fileName))).ToArray());
IUpdateableAssemblyModel model = SD.GetService<IModelFactory>().CreateAssemblyModel(context);
model.Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.ProjectContent.TopLevelTypeDefinitions.ToList());
model.AssemblyName = assembly.ProjectContent.AssemblyName;
model.References = assembly.References.ToList();
return model;
}
public IAssemblyModel GetAssemblyModelSafe(FileName fileName, bool includeInternalMembers = false)
{
try {
return GetAssemblyModel(fileName, includeInternalMembers);
} catch (BadImageFormatException) {
SD.MessageService.ShowWarningFormatted("${res:ICSharpCode.SharpDevelop.Dom.AssemblyInvalid}", Path.GetFileName(fileName));
} catch (FileNotFoundException) {
SD.MessageService.ShowWarningFormatted("${res:ICSharpCode.SharpDevelop.Dom.AssemblyNotAccessible}", fileName);
}
return null;
}
}
}

22
src/Main/SharpDevelop/Parser/ParserDescriptor.cs

@ -3,8 +3,8 @@ @@ -3,8 +3,8 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.SharpDevelop.Parser
{
@ -23,17 +23,11 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -23,17 +23,11 @@ namespace ICSharpCode.SharpDevelop.Parser
public string Language { get; private set; }
public string[] Supportedextensions { get; private set; }
public Regex SupportedFilenamePattern { get; private set; }
public bool CanParse(FileName fileName)
{
string fileExtension = Path.GetExtension(fileName);
foreach (string ext in Supportedextensions) {
if (string.Equals(fileExtension, ext, StringComparison.OrdinalIgnoreCase)) {
return true;
}
}
return false;
return SupportedFilenamePattern.IsMatch(fileName);
}
public ParserDescriptor(Codon codon)
@ -42,20 +36,20 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -42,20 +36,20 @@ namespace ICSharpCode.SharpDevelop.Parser
throw new ArgumentNullException("codon");
this.codon = codon;
this.Language = codon.Id;
this.Supportedextensions = codon.Properties["supportedextensions"].Split(';');
this.SupportedFilenamePattern = new Regex(codon.Properties["supportedfilenamepattern"], RegexOptions.IgnoreCase);
}
public ParserDescriptor(Type parserType, string language, string[] supportedExtensions)
public ParserDescriptor(Type parserType, string language, Regex supportedFilenamePattern)
{
if (parserType == null)
throw new ArgumentNullException("parserType");
if (language == null)
throw new ArgumentNullException("language");
if (supportedExtensions == null)
throw new ArgumentNullException("supportedExtensions");
if (supportedFilenamePattern == null)
throw new ArgumentNullException("supportedFilenamePattern");
this.parserType = parserType;
this.Language = language;
this.Supportedextensions = supportedExtensions;
this.SupportedFilenamePattern = supportedFilenamePattern;
}
}
}

4
src/Main/SharpDevelop/Parser/ParserDoozer.cs

@ -10,8 +10,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -10,8 +10,8 @@ namespace ICSharpCode.SharpDevelop.Parser
/// <summary>
/// Creates ParserDescriptor objects for the parsing service.
/// </summary>
/// <attribute name="supportedextensions">
/// Semicolon-separated list of file extensions for which the parser is used. (e.g. ".boo")
/// <attribute name="supportedfilenamepattern">
/// filename pattern (regex) for which the parser is used. (e.g. "\.(c|cpp|h|hpp)$")
/// </attribute>
/// <attribute name="class">
/// Name of the IParser class.

Loading…
Cancel
Save