[svn] r6901: vs-plugin/trunk: Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/GotoInfo.n Nemerle.Comp...

pbludov svnadmin at nemerle.org
Wed Nov 15 12:51:59 CET 2006


Log:
Navigation is almost done!

Author: pbludov
Date: Wed Nov 15 12:51:54 2006
New Revision: 6901

Modified:
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/GotoInfo.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Type.n
   vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.n
   vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.Designer.cs
   vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.cs
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs
   vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/GotoInfo.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/GotoInfo.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/GotoInfo.n	Wed Nov 15 12:51:54 2006
@@ -27,20 +27,12 @@
       SetLocation(member.Location);
 
       unless (HasLocation)
-      {
-        if (member is IMethod)
-        {
-          // Methods are navigable through a .pdb
-          //
-          _member = member.GetHandle();
+        _member = member.GetHandle()
         }
-        else
+
+    public this(value : ClassMember)
         {
-          // TODO:
-          // For fields: Lookup type, find ctor or any other method and go to it.
-          // For properties & events: Go to getter/setter/adder/etc
-        }
-      }
+      SetLocation(value.Location);
     }
 
     public this(value : LocalValue)
@@ -61,12 +53,17 @@
       _member   = t.GetConstructor(Type.EmptyTypes);
     }
 
+    public this(filePath : string, lineStart : int, colStart : int, lineEnd : int, colEnd : int)
+    {
+      SetLocation(filePath, lineStart, colStart, lineEnd, colEnd)
+    }
+
     private SetLocation(location : Location) : void
     {
       SetLocation(location.File, location.Line, location.Column, location.EndLine, location.EndColumn)
     }
 
-    public SetLocation(filePath : string, lineStart : int, colStart : int, lineEnd : int, colEnd : int) : void
+    private SetLocation(filePath : string, lineStart : int, colStart : int, lineEnd : int, colEnd : int) : void
     {
       _filePath  = filePath;
       _lineStart = lineStart - 1;
@@ -89,11 +86,11 @@
     public override ToString() : string
     {
       if (_lineEnd >= 0)
-        string.Format("{0} {1}:{2} {3}:{4}", _filePath, _lineStart, _colStart, _lineEnd, _colEnd);
+        $"$_filePath $_lineStart:$_colStart $_lineEnd:$_colEnd"
       else if (string.IsNullOrEmpty(_filePath))
-        "<unknown>";
+        "<unknown>"
       else
-        _filePath;
+        _filePath
       }
     }
 

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Type.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Type.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.Type.n	Wed Nov 15 12:51:54 2006
@@ -73,11 +73,6 @@
       }
     }
 
-
-    // PB061114: Ìîæåò ÿâíî äîáàâèòü ïàòòåðíû TExpr.None è PExpr.None è
-    // èñïîëüçîâàòü èõ âìåñòî null? Åù¸ âàðèàíò: èñïîëüçîâàòü option[TExpr] è option[PExpr]
-    // VladD2: À ÷òî ìåøàåò âîçâðàùàòü ïðîñòî null-û äëÿ TExpr è PExpr? Òóò ÿâíî IT âîçâðàùåò íå òîëüêî TExpr è PExpr.
-
     /// Finds an object by provided location.
     /// Returns object location * associated Parsetree * associated Typedtree
     private FindObject(
@@ -103,22 +98,23 @@
               if (loc1.Intersect(loc2) == loc1) m1 else m2
           });
 
-      def checkType(ast, ty)
+      def checkType(pexpr, texpr)
       {
-        def ast_args =
-          match (ast)
+        def pargs =
+          match (pexpr)
           {
           | PExpr.Array  (_, p) => [p]
           | PExpr.Call   (_, p)
-          | PExpr.Indexer(_, p) => p
+          | PExpr.Indexer(_, p)
+          | PExpr.GenericSpecifier(_, p) => p
           | _                   => []
           }
 
-        match (ast_args.Find((p) => p.Location.Contains(line, col)))
+        match (pargs.Find((p) => p.Location.Contains(line, col)))
         {
         | Some(p) =>
-            def ty_args =
-              match (ty)
+            def targs =
+              match (texpr)
               {
               | MType.Array (p, _) => [p]
               | MType.Fun   (f, t) => [f,t]
@@ -127,10 +123,10 @@
               | _                  => []
               }
 
-            def idx = ast_args.IndexOf(p);
-            checkType(p, ty_args.Nth(idx))
+            def idx = pargs.IndexOf(p);
+            checkType(p, targs.Nth(idx))
 
-        | _       => (ast.Location, null, ty)
+        | _       => (pexpr.Location, null, texpr)
         }
       }
 
@@ -235,22 +231,10 @@
     {
       def (_, _, tObj) = FindObject(typeDecl, fileIndex, line, col);
 
-      def getMembers (ti : TypeInfo) {
-        def members = ti.GetMembers(BindingFlags.Static 
-          %| BindingFlags.Instance %| BindingFlags.Public 
-          %| BindingFlags.NonPublic %| BindingFlags.DeclaredOnly)
-          .Filter((p) => System.Attribute.GetCustomAttribute(p.GetHandle(),
-            typeof(CompilerGeneratedAttribute)) == null);
-
-        List.Map(members, GotoInfo);
-      }
-
       def getTypeGotoInfo(tv)
       {
-      | MType.Class(tycon is TypeBuilder, _) =>
-        List.Map(tycon.PartsLocation, GotoInfo);
-
-      | MType.Class(tycon, _)                => getMembers(tycon);
+      | MType.Class(ty is TypeBuilder, _) => List.Map(ty.PartsLocation, GotoInfo);
+      | MType.Class(ty, _)                => [GotoInfo(ty)]
       | _                                    => []
       }
 
@@ -261,11 +245,8 @@
       | tc is TExpr.ImplicitValueTypeCtor => getTypeGotoInfo(tc.ty)
       | tv is TyVar                       => getTypeGotoInfo(tv)
       | tb is TypeBuilder                 => List.Map(tb.PartsLocation, GotoInfo);
-      | ti is TypeInfo                    => getMembers(ti);
       | fh is Typedtree.Fun_header        => [(GotoInfo(fh))]
-      | fb is FieldBuilder                => [(GotoInfo(fb))]
-      | pb is PropertyBuilder             => [(GotoInfo(pb))]
-      | mm is IMember                     => [(GotoInfo(mm))]
+      | m  is IMember                     => [(GotoInfo(m))]
       | _                                 => []
       }
     }

Modified: vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.n
==============================================================================
--- vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.n	(original)
+++ vs-plugin/trunk/Nemerle.Compiler.Utils/Nemerle.Completion2/CodeModel/Project.n	Wed Nov 15 12:51:54 2006
@@ -6,12 +6,14 @@
 using Nemerle.Compiler.Parsetree;
 using Nemerle.Compiler.Typedtree;
 using Nemerle.Compiler.Utils;
+using Nemerle.Collections;
 
 using Nemerle.Assertions;
 using Nemerle.Utility;
 using Nemerle.Imperative;
 
 using SCG = System.Collections.Generic;
+using SR  = System.Reflection;
 
 namespace Nemerle.Completion2
 {
@@ -178,6 +180,28 @@
       }
     }
 
+    public GetGotoInfo(member : SR.MemberInfo) : array [GotoInfo]
+    {
+      def isType = member is System.Type && Attribute.GetCustomAttribute(member, typeof(Nemerle.Internal.VariantOptionAttribute)) == null;
+      def ty = if (isType) member :> System.Type else member.DeclaringType;
+
+      def typeBuilder = Array.Find(NamespaceTree.GetTypeBuilders(), (p) => p.FullName == ty.FullName);
+      if (typeBuilder != null)
+      {
+        def lst = 
+          if (isType)
+            List.Map(typeBuilder.PartsLocation, GotoInfo);
+          else
+            if (typeBuilder.LookupMemberAvailable)
+              List.Map(typeBuilder.GetMembers()      .Filter(m => m.Name == member.Name), GotoInfo);
+            else
+              List.Map(typeBuilder.GetParsedMembers().Filter(m => m.Name == member.Name), GotoInfo);
+        lst.ToArray();
+      }
+      else
+        null
+    }
+
     public GetUsages([NotNull] filePath : string, line : int, col : int) : array [GotoInfo]
     {
       def fileIndex = _compileUnits.GetFileIndex(filePath);

Modified: vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.Designer.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.Designer.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.Designer.cs	Wed Nov 15 12:51:54 2006
@@ -28,7 +28,7 @@
     /// </summary>
     private void InitializeComponent()
     {
-      this._listView = new AutoSizeListView();
+		this._listView = new Nemerle.VisualStudio.GUI.AutoSizeListView();
       this.colFile = new System.Windows.Forms.ColumnHeader();
       this.colLine = new System.Windows.Forms.ColumnHeader();
       this.colPath = new System.Windows.Forms.ColumnHeader();
@@ -46,11 +46,11 @@
       this._listView.Location = new System.Drawing.Point(0, 0);
       this._listView.Name = "_listView";
       this._listView.ShowItemToolTips = true;
-      this._listView.Size = new System.Drawing.Size(555, 272);
+		this._listView.Size = new System.Drawing.Size(292, 274);
       this._listView.TabIndex = 0;
       this._listView.UseCompatibleStateImageBehavior = false;
       this._listView.View = System.Windows.Forms.View.Details;
-      this._listView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseDoubleClick);
+		this._listView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.HandleListViewMouseDoubleClick);
       // 
       // colFile
       // 
@@ -72,7 +72,7 @@
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.ClientSize = new System.Drawing.Size(555, 272);
+		this.ClientSize = new System.Drawing.Size(292, 274);
       this.Controls.Add(this._listView);
       this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
       this.KeyPreview = true;

Modified: vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/GUI/GoToTypeForm.cs	Wed Nov 15 12:51:54 2006
@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
 using System.Drawing;
-using System.Runtime.InteropServices;
 using System.Windows.Forms;
 using Nemerle.Completion2;
 using System.IO;
@@ -33,16 +32,21 @@
 		{
 			base.OnLoad(e);
 
-			// TODO: when the list is large, the form is out of a screen (bound it)
+			Rectangle parentRect = Screen.FromControl(this).WorkingArea;
+
 			// Adjust size
 			//
 			_listView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
+
 			ClientSize = _listView.PreferredSize;
 
+			if (Width  > parentRect.Width *2/3)
+				Width  = parentRect.Width *2/3;
+			if (Height > parentRect.Height*2/3)
+				Height = parentRect.Height*2/3;
+
 			// Adjust position
 			//
-			Rectangle parentRect = Screen.FromControl(this).WorkingArea;
-
 			Left = parentRect.Left + (parentRect.Width  - Width)  / 2;
 			Top  = parentRect.Top  + (parentRect.Height - Height) / 2;
 
@@ -57,13 +61,9 @@
 			base.OnKeyPress(e);
 
 			if (e.KeyChar == (char)Keys.Escape)
-				DialogResult = DialogResult.Cancel;
+				Close(DialogResult.Cancel);
 			else if (e.KeyChar == '\r' || e.KeyChar == ' ')
-				DialogResult = DialogResult.OK;
-			else
-				return;
-
-			Close();
+				Close(DialogResult.OK);
 		}
 
 		protected override void OnFormClosing(FormClosingEventArgs e)
@@ -74,16 +74,21 @@
 				if (_listView.FocusedItem.Tag == null)
 				{
 					e.Cancel = true;
-					MessageBox.Show(this, "You must select item.", "Goto",
+					MessageBox.Show(this, "You must select an item.", "Goto",
 						MessageBoxButtons.OK, MessageBoxIcon.Error);
 				}
 				else
 					Result = (GotoInfo)_listView.FocusedItem.Tag;
 		}
 
-		private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
+		private void HandleListViewMouseDoubleClick(object sender, MouseEventArgs e)
+		{
+			Close(DialogResult.OK);
+		}
+
+		private void Close(DialogResult result)
 		{
-			DialogResult = DialogResult.OK;
+			DialogResult = result;
 			Close();
 		}
 	}

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleAuthoringScope.cs	Wed Nov 15 12:51:54 2006
@@ -1,6 +1,9 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Diagnostics.SymbolStore;
 using System.Windows.Forms;
@@ -57,7 +60,22 @@
 		private ProjectInfo        _project;
 		private string             _filePath;
 		private ISource            _sourceText;
+
+		// Configurable option:
+		//
+		// When true, all files recovered from the .pdb will be recompiled to find real location.
+		// When false, the relevant method locations will be returned.
+		//
+		private bool               _findExactLocation = true;
+
+		#endregion
+
+		#region Constants
+
 		private /*readonly*/ Guid   IID_MetaDataImport = new Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44");
+		private const BindingFlags  AllMethods         = BindingFlags.DeclaredOnly
+										| BindingFlags.Instance | BindingFlags.Static
+										| BindingFlags.Public | BindingFlags.NonPublic;
 
 		#endregion
 
@@ -115,31 +133,27 @@
 				return null;
 			}
 
-			LookupMethodLocationsFromPdb(info);
-
-			List<GotoInfo> gotoInfos = new List<GotoInfo>(info.Length);
-
-			// Remove duplicates and members which location still is not known.
-			//
-			for (int i = 0; i < info.Length; ++i)
+			if (!info[0].HasLocation)
 			{
-				if (info[i].HasLocation && gotoInfos.FindIndex(
-						delegate (GotoInfo item)
+				Debug.Assert(info.Length == 1, "Multiple unknown locations are unexpected");
+				info = LookupLocationsFromPdb(info[0]);
+
+				if (info == null)
 						{
-							return item.FilePath  == info[i].FilePath
-								&& item.LineStart == info[i].LineStart;
-						}) < 0)
-					gotoInfos.Add(info[i]);
+					// PB061115: Generate code here
+					//
+					return null;
+				}
 			}
 
-			if (gotoInfos.Count == 1)
-				return SetTextSpan(ref span, gotoInfos[0]);
-			else if (gotoInfos.Count > 0)
+			if (info.Length == 1)
+				return SetTextSpan(ref span, info[0]);
+			else if (info.Length > 0)
 			{
 				NativeWindow textEditorWnd = 
 					NativeWindow.FromHandle(textView.GetWindowHandle());
 
-				using (GoToTypeForm popup = new GoToTypeForm(gotoInfos))
+				using (GoToTypeForm popup = new GoToTypeForm(info))
 					if (popup.ShowDialog(textEditorWnd) == DialogResult.OK)
 						return SetTextSpan(ref span, popup.Result);
 			}
@@ -162,38 +176,33 @@
 
 		#region Implementation
 
-		private void LookupMethodLocationsFromPdb(GotoInfo[] info)
+		private GotoInfo[] LookupLocationsFromPdb(GotoInfo info)
 		{
-			IntPtr            mdiPtr     = IntPtr.Zero;
-			ISymbolBinder1    binder     = null;
-			ISymbolDocument[] documents  = null;
-			int[]             lines      = null;
-			int[]             columns    = null;
-			int[]             endLines   = null;
-			int[]             endColumns = null;
-			int[]             offsets    = null;
-			string            prevFile   = null;
-			ISymbolReader     reader     = null;
+			Debug.Assert(info != null, "LookupLocationsFromPdb lacks required parameter");
 
-			try
-			{
-				foreach (GotoInfo gotoInfo in info)
-				{
-					if (gotoInfo.HasLocation)
-						continue;
-					if (gotoInfo.Member == null || string.IsNullOrEmpty(gotoInfo.FilePath))
-						continue;
+			if (info.Member == null || string.IsNullOrEmpty(info.FilePath) || !File.Exists(info.FilePath))
+				return new GotoInfo[0];
 
-					// First time init
-					//
-					if (mdiPtr == IntPtr.Zero)
-					{
-						object mdiUnk;
+			object            unkMetaDataImport;
+			IntPtr            ptrMetaDataImport;
+			ISymbolBinder1    binder;
+			ISymbolReader     reader;
+			ISymbolDocument[] documents;
+			int[]             lines;
+			int[]             columns;
+			int[]             endLines;
+			int[]             endColumns;
+			int[]             offsets;
+			int               hr;
+			List<GotoInfo>    infos      = new List<GotoInfo>();
+			List<MethodBase>  methods    = new List<MethodBase>();
 
-						if (VSConstants.S_OK == _project.SmartOpenScope.OpenScope(info[0].FilePath, 0, ref IID_MetaDataImport, out mdiUnk))
+			hr = _project.SmartOpenScope.OpenScope(info.FilePath, 0, ref IID_MetaDataImport, out unkMetaDataImport);
+			if (hr == VSConstants.S_OK)
 						{
-							mdiPtr     = Marshal.GetIUnknownForObject(mdiUnk);
+				ptrMetaDataImport = Marshal.GetIUnknownForObject(unkMetaDataImport);
 							binder     = new SymBinder();
+				reader            = binder.GetReader(ptrMetaDataImport, info.FilePath, null);
 							documents  = new ISymbolDocument[1];
 							lines      = new int[1];
 							columns    = new int[1];
@@ -203,34 +212,68 @@
 						}
 						else
 						{
-							Debug.WriteLineIf(TS.TraceWarning, "Failed to obtain MetaDataImport from VS", TS.DisplayName);
-							break;
-						}
+				Debug.WriteLineIf(TS.TraceWarning,
+					string.Format("Failed to obtain MetaDataImport from VS, hr 0x{0:X8}", hr), TS.DisplayName);
+				return null;
 					}
 
 					try
 					{
-						if (gotoInfo.FilePath != prevFile)
+				if (info.Member is MethodBase)
+					methods.Add((MethodBase)info.Member);
+				else if (info.Member is PropertyInfo)
 						{
-							reader   = binder.GetReader(mdiPtr, gotoInfo.FilePath, null);
-							prevFile = gotoInfo.FilePath;
+					PropertyInfo pi = (PropertyInfo)info.Member;
+					methods.AddRange(pi.GetAccessors(true));
 						}
+				else if (info.Member is FieldInfo)
+				{
+					Type t = info.Member.DeclaringType;
+					methods.AddRange(t.GetMethods(AllMethods));
+				}
+				else if (info.Member is EventInfo)
+				{
+					EventInfo ei = (EventInfo)info.Member;
+					methods.Add     (ei.GetAddMethod   (true));
+					methods.Add     (ei.GetRemoveMethod(true));
+					methods.Add     (ei.GetRaiseMethod (true));
+					methods.AddRange(ei.GetOtherMethods(true));
+				}
+				else if (info.Member is Type)
+				{
+					Type t = (Type)info.Member;
+					methods.AddRange(t.GetMethods(AllMethods));
+				}
+				else
+					Trace.Fail("Unexpected MemberInfo " + info.Member.GetType().FullName);
 
-						SymbolToken   token  = new SymbolToken(gotoInfo.Member.MetadataToken);
+				foreach (MethodBase mb in methods)
+				{
+					if (Attribute.GetCustomAttribute(mb, typeof(CompilerGeneratedAttribute)) != null)
+						continue;
+
+					try
+					{
+						SymbolToken   token  = new SymbolToken(mb.MetadataToken);
 						ISymbolMethod method = reader.GetMethod(token);
 
 						if (method.SequencePointCount > 0)
 						{
 							method.GetSequencePoints(offsets, documents, lines, columns, endLines, endColumns);
-							gotoInfo.SetLocation(documents[0].URL, lines[0], columns[0], endLines[0], endColumns[0]);
+
+							// We are interested in unique files only.
+							//
+							if (infos.Find(delegate (GotoInfo item){ return item.FilePath == documents[0].URL; }) == null)
+								infos.Add(new GotoInfo(documents[0].URL, lines[0], columns[0], endLines[0], endColumns[0]));
 						}
 					}
 					catch (COMException ex)
 					{
-						// Abstract method or not a method at all. Sequence points are available only for methods.
+						// Abstract method or not a method at all.
+						// Sequence points are available only for methods.
 						//
 						Trace.WriteLineIf(TS.TraceError,
-							string.Format("{0}, code 0x{1:X8}", ex.Message, ex.ErrorCode), TS.DisplayName);
+							string.Format("({0}) {1}, code 0x{2:X8}", mb.Name, ex.Message, ex.ErrorCode), TS.DisplayName);
 					}
 				}
 			}
@@ -243,9 +286,34 @@
 			}
 			finally
 			{
-				if (IntPtr.Zero != mdiPtr)
-					Marshal.Release(mdiPtr);
+				if (IntPtr.Zero != ptrMetaDataImport)
+					Marshal.Release(ptrMetaDataImport);
 			}
+
+			// In case of a Method we already succeeded
+			//
+			if (info.Member is MethodBase)
+			{
+				Debug.Assert(infos.Count < 2, "Partial method is not expected.");
+				return infos.ToArray();
+			}
+
+			if (_findExactLocation)
+			{
+				// Quickly compile and find the _exact_ location(s)
+				//
+				Nemerle.Completion2.ProjectManager pm = new Nemerle.Completion2.ProjectManager();
+				Nemerle.Completion2.Engine         e  = new Nemerle.Completion2.Engine(pm, new TraceWriter());
+
+				pm.Engine = e;
+
+				foreach (GotoInfo gi in infos)
+					e.Sources.AddOrUpdate(gi.FilePath, File.ReadAllText(gi.FilePath));
+
+				return e.Project.GetGotoInfo(info.Member);
+			}
+
+			return infos.ToArray();
 		}
 
 		private static string SetTextSpan(ref TextSpan span, GotoInfo result)

Modified: vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/LanguageService/NemerleLanguageService.cs	Wed Nov 15 12:51:54 2006
@@ -252,12 +252,13 @@
 			{
 
 				ProjectInfo projectInfo = ProjectInfo.FindProject(request.FileName);
-				Nemerle.Completion2.Project p = projectInfo.Engine.Project;
-				Trace.Assert(p != null);
 
 				if (projectInfo == null)
 					return null;
 
+				Nemerle.Completion2.Project p = projectInfo.Engine.Project;
+				Trace.Assert(p != null);
+
 				NemerleSource source = projectInfo.GetSource(request.FileName);
 
 				int nErrors = 0;



More information about the svn mailing list