[Monodevelop-patches-list] r1667 - in trunk/MonoDevelop/src/Main/Base: . Services/ParserService

commit-watcher at mono-cvs.ximian.com commit-watcher at mono-cvs.ximian.com
Sun May 30 14:19:41 EDT 2004


Author: lluis
Date: 2004-05-30 14:19:41 -0400 (Sun, 30 May 2004)
New Revision: 1667

Modified:
   trunk/MonoDevelop/src/Main/Base/ChangeLog
   trunk/MonoDevelop/src/Main/Base/Services/ParserService/CodeCompletionDatabase.cs
   trunk/MonoDevelop/src/Main/Base/Services/ParserService/DefaultParserService.cs
   trunk/MonoDevelop/src/Main/Base/Services/ParserService/IParserService.cs
Log:
	* Services/ParserService/DefaultParserService.cs: Don't use the "Gac:"
	  prefix to reference gac assemblies, they are handled internally by
	  AssemblyCodeCompletionDatabase.
	  When locating an assembly database, take into account partial names,
	  and avoid loading the same db twice.
	  Perform the modified file check taking into account dependencies
	  between databases. This increases the posibility of resolving all classes
	  of a database in the first parse cycle (since its dependecies will be
	  already parsed).
	  Added parameter to GetClass which allows deep search of a class in all
	  project references.
	  In ResolveTypes, added out parameter to inform if all types could be
	  resolved.
	  In ClassInheritanceEnumerator, use a reference deep search to get base
	  classes.
	  
	* IParserService.cs: Added parameter to GetClass which allows deep search of
	  a class in all project references.
	  
	* CodeCompletionDatabase.cs: Increased db version, since the format has
	  changed a bit. Added an easy way for derived classes to serialize data
	  together with the index.
	  When writing the db, make a byte copy from the old file to the new one
	  for classes not loaded.
	  In ProjectCodeCompletionDatabase, if a file can't be fully resolved,
	  schedule a reparse.
	  In GetClass() support lookup of inner classes. Improved some internal
	  methods to support this.



Modified: trunk/MonoDevelop/src/Main/Base/ChangeLog
===================================================================
--- trunk/MonoDevelop/src/Main/Base/ChangeLog	2004-05-30 05:30:41 UTC (rev 1666)
+++ trunk/MonoDevelop/src/Main/Base/ChangeLog	2004-05-30 18:19:41 UTC (rev 1667)
@@ -1,3 +1,34 @@
+2004-05-30  Lluis Sanchez Gual  <lluis at ximian.com>
+
+	* Services/ParserService/DefaultParserService.cs: Don't use the "Gac:"
+	  prefix to reference gac assemblies, they are handled internally by
+	  AssemblyCodeCompletionDatabase.
+	  When locating an assembly database, take into account partial names,
+	  and avoid loading the same db twice.
+	  Perform the modified file check taking into account dependencies
+	  between databases. This increases the posibility of resolving all classes
+	  of a database in the first parse cycle (since its dependecies will be
+	  already parsed).
+	  Added parameter to GetClass which allows deep search of a class in all
+	  project references.
+	  In ResolveTypes, added out parameter to inform if all types could be
+	  resolved.
+	  In ClassInheritanceEnumerator, use a reference deep search to get base
+	  classes.
+	  
+	* IParserService.cs: Added parameter to GetClass which allows deep search of
+	  a class in all project references.
+	  
+	* CodeCompletionDatabase.cs: Increased db version, since the format has
+	  changed a bit. Added an easy way for derived classes to serialize data
+	  together with the index.
+	  When writing the db, make a byte copy from the old file to the new one
+	  for classes not loaded.
+	  In ProjectCodeCompletionDatabase, if a file can't be fully resolved,
+	  schedule a reparse.
+	  In GetClass() support lookup of inner classes. Improved some internal
+	  methods to support this.
+
 2004-05-29  Todd Berman  <tberman at sevenl.net>
 
 	* Services/Project/DefaultProjectService.cs: try catch around

Modified: trunk/MonoDevelop/src/Main/Base/Services/ParserService/CodeCompletionDatabase.cs
===================================================================
--- trunk/MonoDevelop/src/Main/Base/Services/ParserService/CodeCompletionDatabase.cs	2004-05-30 05:30:41 UTC (rev 1666)
+++ trunk/MonoDevelop/src/Main/Base/Services/ParserService/CodeCompletionDatabase.cs	2004-05-30 18:19:41 UTC (rev 1667)
@@ -28,7 +28,7 @@
 	{
 		static readonly int MAX_ACTIVE_COUNT = 100;
 		static readonly int MIN_ACTIVE_COUNT = 50;
-		static readonly int FORMAT_VERSION = 2;
+		static protected readonly int FORMAT_VERSION = 3;
 		
 		NamespaceEntry rootNamespace;
 		protected ArrayList references;
@@ -55,6 +55,11 @@
 			headers = new Hashtable ();
 		}
 		
+		public string DataFile
+		{
+			get { return dataFile; }
+		}
+		
 		protected void SetLocation (string basePath, string name)
 		{
 			dataFile = Path.Combine (basePath, name + ".pidb");
@@ -108,11 +113,14 @@
 					ifile.Position = indexOffset;
 					
 					object[] data = (object[]) bf.Deserialize (ifile);
+					Queue dataQueue = new Queue (data);
+					references = (ArrayList) dataQueue.Dequeue ();
+					rootNamespace = (NamespaceEntry)  dataQueue.Dequeue ();
+					files = (Hashtable)  dataQueue.Dequeue ();
+					DeserializeData (dataQueue);
+
 					ifile.Close ();
 					
-					references = (ArrayList) data[0];
-					rootNamespace = (NamespaceEntry) data[1];
-					files = (Hashtable) data[2];
 				}
 				catch (Exception ex)
 				{
@@ -160,6 +168,9 @@
 				long indexOffsetPos = dfile.Position;
 				bw.Write ((long)0);
 				
+				MemoryStream buffer = new MemoryStream ();
+				BinaryWriter bufWriter = new BinaryWriter (buffer);
+				
 				// Write all class data
 				foreach (FileEntry fe in files.Values) 
 				{
@@ -167,20 +178,44 @@
 					while (ce != null)
 					{
 						IClass c = ce.Class;
-						if (c == null)
-							c = ReadClass (ce);
-							
+						byte[] data;
+						int len;
+						
+						if (c == null) {
+							// Copy the data from the source file
+							if (datareader == null) {
+								datafile = new FileStream (dataFile, FileMode.Open, FileAccess.Read, FileShare.Read);
+								datareader = new BinaryReader (datafile);
+							}
+							datafile.Position = ce.Position;
+							len = datareader.ReadInt32 ();
+							data = new byte[len];
+							datafile.Read (data, 0, len);
+						}
+						else {
+							buffer.Position = 0;
+							PersistentClass.WriteTo (c, bufWriter, parserService.DefaultNameEncoder);
+							data = buffer.GetBuffer ();
+							len = (int)buffer.Position;
+						}
+						
 						ce.Position = dfile.Position;
-						PersistentClass.WriteTo (c, bw, parserService.DefaultNameEncoder);
+						bw.Write (len);
+						bw.Write (data, 0, len);
 						ce = ce.NextInFile;
 					}
 				}
 				
 				// Write the index
 				long indexOffset = dfile.Position;
-				object[] data = new object[] { references, rootNamespace, files };
-				bf.Serialize (dfile, data);
 				
+				Queue dataQueue = new Queue ();
+				dataQueue.Enqueue (references);
+				dataQueue.Enqueue (rootNamespace);
+				dataQueue.Enqueue (files);
+				SerializeData (dataQueue);
+				bf.Serialize (dfile, dataQueue.ToArray ());
+				
 				dfile.Position = indexOffsetPos;
 				bw.Write (indexOffset);
 				
@@ -193,11 +228,17 @@
 					File.Delete (dataFile);
 					
 				File.Move (tmpDataFile, dataFile);
-				
-				Console.WriteLine ("Done Writing " + tmpDataFile);
 			}
 		}
 		
+		protected virtual void SerializeData (Queue dataQueue)
+		{
+		}
+		
+		protected virtual void DeserializeData (Queue dataQueue)
+		{
+		}
+				
 		void Flush ()
 		{
 			int activeCount = 0;
@@ -231,6 +272,7 @@
 				datareader = new BinaryReader (datafile);
 			}
 			datafile.Position = ce.Position;
+			datareader.ReadInt32 ();	// Length of data
 			return PersistentClass.Read (datareader, parserService.DefaultNameDecoder);
 		}
 		
@@ -246,14 +288,41 @@
 		{
 			lock (rwlock)
 			{
+//				Console.WriteLine ("GET CLASS " + typeName + " in " + dataFile);
 				string[] path = typeName.Split ('.');
 				int len = path.Length - 1;
-				NamespaceEntry nst = GetNamespaceEntry (path, len, false, caseSensitive);
-				if (nst == null) return null;
-	
-				ClassEntry ce = nst.GetClass (path[len], caseSensitive);
-				if (ce == null) return null;
-				return GetClass (ce);
+				
+				NamespaceEntry nst;
+				int nextPos;
+				
+				if (GetBestNamespaceEntry (path, len, false, caseSensitive, out nst, out nextPos)) 
+				{
+					ClassEntry ce = nst.GetClass (path[len], caseSensitive);
+					if (ce == null) return null;
+					return GetClass (ce);
+				}
+				else
+				{
+					// It may be an inner class
+					ClassEntry ce = nst.GetClass (path[nextPos++], caseSensitive);
+					if (ce == null) return null;
+					
+					len++;	// Now include class name
+					IClass c = GetClass (ce);
+					
+					while (nextPos < len) {
+						IClass nextc = null;
+						for (int n=0; n<c.InnerClasses.Count && nextc == null; n++) {
+							IClass innerc = c.InnerClasses[n];
+							if (string.Compare (innerc.Name, path[nextPos], !caseSensitive) == 0)
+								nextc = innerc;
+						}
+						if (nextc == null) return null;
+						c = nextc;
+						nextPos++;
+					}
+					return c;
+				}
 			}
 		}
 		
@@ -276,7 +345,7 @@
 				{
 					if (!File.Exists (file.FileName)) continue;
 					FileInfo fi = new FileInfo (file.FileName);
-					if (fi.LastWriteTime > file.LastParseTime) 
+					if (fi.LastWriteTime > file.LastParseTime || file.ParseErrorRetries > 0) 
 					{
 						// Change date now, to avoid reparsing if CheckModifiedFiles is called again
 						// before the parse job is executed
@@ -311,7 +380,6 @@
 		
 		protected void AddReference (string uri)
 		{
-			Console.WriteLine ("AddReference " + uri);
 			lock (rwlock)
 			{
 				ReferenceEntry re = new ReferenceEntry (uri);
@@ -322,7 +390,6 @@
 		
 		protected void RemoveReference (string uri)
 		{
-			Console.WriteLine ("RemoveReference " + uri);
 			lock (rwlock)
 			{
 				for (int n=0; n<references.Count; n++)
@@ -336,6 +403,16 @@
 			}
 		}
 		
+		protected bool HasReference (string uri)
+		{
+			for (int n=0; n<references.Count; n++) {
+				ReferenceEntry re = (ReferenceEntry) references[n];
+				if (((ReferenceEntry) references[n]).Uri == uri)
+					return true;
+			}
+			return false;
+		}
+		
 		public void AddFile (string fileName)
 		{
 			lock (rwlock)
@@ -364,29 +441,6 @@
 			}
 		}
 		
-		protected void AddClass (IClass c, FileEntry fe)
-		{
-			lock (rwlock)
-			{
-				string[] path = c.Namespace.Split ('.');
-				NamespaceEntry nst = GetNamespaceEntry (path, path.Length, true, true);
-				ClassEntry ce = nst.GetClass (c.Name, true);
-				if (ce == null) {
-					ce = new ClassEntry (c, fe, nst);
-					nst.Add (c.Name, ce);
-				}
-				else {
-					ce.Class = CopyClass (c);
-				}
-				
-				if (ce.FileEntry != fe)
-					fe.AddClass (ce);
-	
-				ce.LastGetTime = currentGetTime++;
-				modified = true;
-			}
-		}
-			
 		public ClassUpdateInformation UpdateClassInformation (ClassCollection newClasses, string fileName)
 		{
 			lock (rwlock)
@@ -524,27 +578,44 @@
 			return PersistentClass.Read (br, parserService.DefaultNameDecoder);
 		}
 		
-		NamespaceEntry GetNamespaceEntry (string[] path, int length, bool createPath, bool caseSensitive)
+		bool GetBestNamespaceEntry (string[] path, int length, bool createPath, bool caseSensitive, out NamespaceEntry lastEntry, out int numMatched)
 		{
-			NamespaceEntry nst = rootNamespace;
+			lastEntry = rootNamespace;
 
 			if (length == 0 || (length == 1 && path[0] == "")) {
-				return nst;
+				numMatched = length;
+				return true;
 			}
 			else
 			{
 				for (int n=0; n<length; n++) {
-					NamespaceEntry nh = nst.GetNamespace (path[n], caseSensitive);
+					NamespaceEntry nh = lastEntry.GetNamespace (path[n], caseSensitive);
 					if (nh == null) {
-						if (!createPath) return null;
+						if (!createPath) {
+							numMatched = n;
+							return false;
+						}
+						
 						nh = new NamespaceEntry ();
-						nst.Add (path[n], nh);
+						lastEntry.Add (path[n], nh);
 					}
-					nst = nh;
+					lastEntry = nh;
 				}
-				return nst;
+				numMatched = length;
+				return true;
 			}
 		}
+		
+		NamespaceEntry GetNamespaceEntry (string[] path, int length, bool createPath, bool caseSensitive)
+		{
+			NamespaceEntry nst;
+			int matched;
+			
+			if (GetBestNamespaceEntry (path, length, createPath, caseSensitive, out nst, out matched))
+				return nst;
+			else
+				return null;
+		}
 	}
 	
 	internal class ProjectCodeCompletionDatabase: CodeCompletionDatabase
@@ -584,17 +655,14 @@
 			fs.Clear ();
 			foreach (ProjectReference pr in project.ProjectReferences)
 			{
-				string refId = pr.ReferenceType + ":" + pr.Reference;
+				string refId = pr.ReferenceType == ReferenceType.Project ? "Project" : "Assembly";
+				refId += ":" + pr.Reference;
+
 				if (pr.ReferenceType == ReferenceType.Gac && refId.ToLower().EndsWith (".dll"))
 					refId = refId.Substring (0, refId.Length - 4);
 
 				fs[refId] = null;
-				bool found = false;
-				for (int n=0; n<references.Count && !found; n++) {
-					ReferenceEntry re = (ReferenceEntry) references[n];
-					found = ((ReferenceEntry) references[n]).Uri == refId;
-				}
-				if (!found)
+				if (!HasReference (refId))
 					AddReference (refId);
 			}
 			
@@ -611,11 +679,34 @@
 		{
 			IParseInformation parserInfo = parserService.DoParseFile ((string)fileName, null);
 			ICompilationUnit cu = (ICompilationUnit)parserInfo.BestCompilationUnit;
+			
+			ClassUpdateInformation res = UpdateFromParseInfo (parserInfo, fileName);
+			parserService.NotifyParseInfoChange (fileName, res);
+		}
+		
+		public ClassUpdateInformation UpdateFromParseInfo (IParseInformation parserInfo, string fileName)
+		{
+			ICompilationUnit cu = (ICompilationUnit)parserInfo.BestCompilationUnit;
 
-			ClassCollection resolved = parserService.ResolveTypes (project, cu, cu.Classes);
+			ClassCollection resolved;
+			bool allResolved = parserService.ResolveTypes (project, cu, cu.Classes, out resolved);
 			ClassUpdateInformation res = UpdateClassInformation (resolved, fileName);
 			
-			parserService.NotifyParseInfoChange (fileName, res);
+			FileEntry file = files [fileName] as FileEntry;
+			
+			if (!allResolved) {
+				if (file.ParseErrorRetries > 0) {
+					file.ParseErrorRetries--;
+				}
+				else {
+					file.ParseErrorRetries = 3;
+				}
+			}
+			else {
+				file.ParseErrorRetries = 0;
+			}
+
+			return res;
 		}
 	}
 	
@@ -630,25 +721,40 @@
 		{
 			string assemblyFile;
 			string name;
+			Assembly asm = null;
 			
-			this.assemblyName = assemblyName;
-			
-			if (assemblyName == "mscorlib") {
-				name = assemblyName;
-				assemblyFile = typeof(object).Assembly.Location;
-			}
-			else if (assemblyName.ToLower().EndsWith (".dll")) {
+			if (assemblyName.ToLower().EndsWith (".dll")) 
+			{
 				name = assemblyName.Substring (0, assemblyName.Length - 4);
 				name = name.Replace(',','_').Replace(" ","").Replace('/','_');
 				assemblyFile = assemblyName;
+				try {
+					asm = Assembly.LoadFrom (assemblyFile);
+				}
+				catch {}
+				
+				if (asm == null) {
+					Console.WriteLine ("Could not load assembly: " + assemblyFile);
+					return;
+				}
 			}
-			else {
-				assemblyName = GetAssemblyFullName (assemblyName);
+			else 
+			{
+				asm = FindAssembly (assemblyName);
+				
+				if (asm == null) {
+					Console.WriteLine ("Could not load assembly: " + assemblyName);
+					return;
+				}
+				
+				assemblyName = asm.GetName().FullName;
 				name = EncodeGacAssemblyName (assemblyName);
-				assemblyFile = GetGacAssemblyLocation (assemblyName);
+				assemblyFile = asm.Location;
 			}
 			
+			this.assemblyName = assemblyName;
 			this.baseDir = baseDir;
+			
 			SetLocation (baseDir, name);
 
 			Read ();
@@ -657,8 +763,56 @@
 				AddFile (assemblyFile);
 				headers ["CheckFile"] = assemblyFile;
 			}
+			
+			// Update references to other assemblies
+			
+			Hashtable rs = new Hashtable ();
+			foreach (AssemblyName aname in asm.GetReferencedAssemblies ()) {
+				string uri = "Assembly:" + aname.ToString();
+				rs[uri] = null;
+				if (!HasReference (uri))
+					AddReference (uri);
+			}
+			
+			ArrayList keys = new ArrayList ();
+			keys.AddRange (references);
+			foreach (ReferenceEntry re in keys)
+			{
+				if (!rs.Contains (re.Uri))
+					RemoveReference (re.Uri);
+			}
 		}
 		
+		public static string GetFullAssemblyName (string s)
+		{
+			if (s.ToLower().EndsWith (".dll")) 
+				return s;
+				
+			Assembly asm = FindAssembly (s);
+			
+			if (asm != null)
+				return asm.GetName().FullName;
+			else
+				return s;
+		}
+		
+		public static Assembly FindAssembly (string name)
+		{
+			Assembly asm = null;
+			try {
+				asm = Assembly.Load (name);
+			}
+			catch {}
+			
+			if (asm == null) {
+				try {
+					asm = Assembly.LoadWithPartialName (name);
+				}
+				catch {}
+			}
+			return asm;
+		}
+		
 		string EncodeGacAssemblyName (string assemblyName)
 		{
 			string[] assemblyPieces = assemblyName.Split(',');
@@ -673,38 +827,18 @@
 			return res;
 		}
 		
-		string GetGacAssemblyLocation (string assemblyName)
+		public string AssemblyName
 		{
-			Assembly asm;
-			try {
-				asm = Assembly.Load (assemblyName);
-			}
-			catch {
-				asm = Assembly.LoadWithPartialName (assemblyName);
-			}
-			
-			if (asm == null)
-				throw new InvalidOperationException ("Could not find: " + assemblyName);
-
-			return asm.Location;
+			get { return assemblyName; }
 		}
 		
-		public string GetAssemblyFullName (string assemblyName)
-		{
-			if (assemblyName.IndexOf (',') == -1) return assemblyName;
-			Assembly asm = Assembly.LoadWithPartialName (assemblyName);
-			return asm.GetName().FullName;
-		}
-		
 		protected override void ParseFile (string fileName)
 		{
 			if (useExternalProcess)
 			{
 				string dbgen = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "dbgen.exe");
-				Console.WriteLine ("Starting " + dbgen);
 				Process proc = Process.Start ("mono " + dbgen, "\"" + baseDir + "\" \"" + assemblyName + "\"");
 				proc.WaitForExit ();
-				Console.WriteLine ("Done " + proc.ExitCode);
 				Read ();
 			}
 			else
@@ -727,10 +861,10 @@
 			// Read the headers of the file without fully loading the database
 			Hashtable headers = ReadHeaders (baseDir, name);
 			string checkFile = (string) headers ["CheckFile"];
-			if (!File.Exists (checkFile)) {
+			int version = (int) headers ["Version"];
+			if (!File.Exists (checkFile) || version != FORMAT_VERSION) {
 				string dataFile = Path.Combine (baseDir, name + ".pidb");
 				File.Delete (dataFile);
-				Console.WriteLine ("File not exists: " + checkFile);
 				Console.WriteLine ("Deleted " + dataFile);
 			}
 		}
@@ -931,6 +1065,7 @@
 		string filePath;
 		DateTime parseTime;
 		ClassEntry firstClass;
+		int parseErrorRetries;
 		
 		public FileEntry (string path)
 		{
@@ -954,6 +1089,12 @@
 			get { return firstClass; }
 		}
 		
+		public int ParseErrorRetries
+		{
+			get { return parseErrorRetries; }
+			set { parseErrorRetries = value; }
+		}
+		
 		public void SetClasses (ArrayList list)
 		{
 			firstClass = null;

Modified: trunk/MonoDevelop/src/Main/Base/Services/ParserService/DefaultParserService.cs
===================================================================
--- trunk/MonoDevelop/src/Main/Base/Services/ParserService/DefaultParserService.cs	2004-05-30 05:30:41 UTC (rev 1666)
+++ trunk/MonoDevelop/src/Main/Base/Services/ParserService/DefaultParserService.cs	2004-05-30 18:19:41 UTC (rev 1667)
@@ -35,7 +35,7 @@
 		CodeCompletionDatabase coreDatabase;
 		
 		const int MAX_CACHE_SIZE = 10;
-		const string CoreDB = "Assembly:mscorlib";
+		string CoreDB;
 
 		class ParsingCacheEntry
 		{
@@ -56,6 +56,7 @@
 			IProject project;
 			ICompilationUnit unit;
 			DefaultParserService parserService;
+			bool allResolved;
 			
 			public CompilationUnitTypeResolver (IProject project, ICompilationUnit unit, DefaultParserService parserService)
 			{
@@ -69,9 +70,17 @@
 				IClass c = parserService.SearchType (project, typeName, CallingClass, unit);
 				if (c != null)
 					return c.FullyQualifiedName;
-				else
+				else {
+					allResolved = false;
 					return typeName;
+				}
 			}
+			
+			public bool AllResolved
+			{
+				get { return allResolved; }
+				set { allResolved = value; }
+			}
 		}
 		
 		Hashtable lastUpdateSize = new Hashtable();
@@ -208,7 +217,7 @@
 		
 		public void GenerateAssemblyDatabase (string baseDir, string name)
 		{
-			AssemblyCodeCompletionDatabase db = GetDatabase (baseDir, "Assembly:" + name) as AssemblyCodeCompletionDatabase;
+			AssemblyCodeCompletionDatabase db = new AssemblyCodeCompletionDatabase (baseDir, name, this);
 			db.ParseInExternalProcess = false;
 			db.ParseAll ();
 			db.Write ();
@@ -232,7 +241,9 @@
 			SetDefaultCompletionFileLocation();
 			DeleteObsoleteDatabases ();
 
-			coreDatabase = new AssemblyCodeCompletionDatabase (codeCompletionPath, "mscorlib", this);
+			string coreName = typeof(object).Assembly.GetName().ToString ();
+			CoreDB = "Assembly:" + coreName;
+			coreDatabase = new AssemblyCodeCompletionDatabase (codeCompletionPath, coreName, this);
 			databases [CoreDB] = coreDatabase;
 			
 			IProjectService projectService = (IProjectService)MonoDevelop.Core.Services.ServiceManager.Services.GetService(typeof(IProjectService));
@@ -265,19 +276,31 @@
 				if (db == null) 
 				{
 					// Create/load the database
-						
+
 					if (uri.StartsWith ("Assembly:"))
 					{
 						string file = uri.Substring (9);
-						db = new AssemblyCodeCompletionDatabase (baseDir, file, this);
+						
+						// We may be trying to load an assembly db using a partial name.
+						// In this case we get the full name to avoid database conflicts
+						file = AssemblyCodeCompletionDatabase.GetFullAssemblyName (file);
+						string realUri = "Assembly:" + file;
+						db = (CodeCompletionDatabase) databases [realUri];
+						if (db != null) {
+							databases [uri] = db;
+							return db;
+						}
+						
+						AssemblyCodeCompletionDatabase adb;
+						db = adb = new AssemblyCodeCompletionDatabase (baseDir, file, this);
+						databases [realUri] = adb;
+						if (uri != realUri)
+							databases [uri] = adb;
+						
+						// Load referenced databases
+						foreach (ReferenceEntry re in db.References)
+							GetDatabase (baseDir, re.Uri);
 					}
-					else if (uri.StartsWith ("Gac:"))
-					{
-						string file = uri.Substring (4);
-						db = new AssemblyCodeCompletionDatabase (baseDir, file, this);
-					}
-					if (db != null)
-						databases [uri] = db;
 				}
 				return db;
 			}
@@ -483,13 +506,58 @@
 		
 		void CheckModifiedFiles ()
 		{
+			// Check databases following a bottom-up strategy in the dependency
+			// tree. This will help resolving parsed classes.
+			
 			ArrayList list = new ArrayList ();
-			lock (databases) {
-				list.AddRange (databases.Values);
+			lock (databases) 
+			{
+				// There may be several uris for the same db
+				foreach (object ob in databases.Values)
+					if (!list.Contains (ob))
+						list.Add (ob);
 			}
 			
-			foreach (CodeCompletionDatabase db in list) 
-				db.CheckModifiedFiles ();
+			ArrayList done = new ArrayList ();
+			while (list.Count > 0) 
+			{
+				CodeCompletionDatabase readydb = null;
+				CodeCompletionDatabase bestdb = null;
+				int bestRefCount = int.MaxValue;
+				
+				// Look for a db with all references resolved
+				for (int n=0; n<list.Count && readydb==null; n++)
+				{
+					CodeCompletionDatabase db = (CodeCompletionDatabase)list[n];
+
+					bool allDone = true;
+					foreach (ReferenceEntry re in db.References) {
+						CodeCompletionDatabase refdb = GetDatabase (re.Uri);
+						if (!done.Contains (refdb)) {
+							allDone = false;
+							break;
+						}
+					}
+					
+					if (allDone)
+						readydb = db;
+					else if (db.References.Count < bestRefCount) {
+						bestdb = db;
+						bestRefCount = db.References.Count;
+					}
+				}
+
+				// It may not find any db without resolved references if there
+				// are circular dependencies. In this case, take the one with
+				// less references
+				
+				if (readydb == null)
+					readydb = bestdb;
+					
+				readydb.CheckModifiedFiles ();
+				list.Remove (readydb);
+				done.Add (readydb);
+			}
 		}
 		
 		void ConsumeParsingQueue ()
@@ -549,9 +617,7 @@
 						
 						ProjectCodeCompletionDatabase db = GetProjectDatabase (viewContent.Project);
 						if (db != null) {
-							ICompilationUnit cu = (ICompilationUnit)parseInformation.BestCompilationUnit;
-							ClassCollection resolved = ResolveTypes (viewContent.Project, cu, cu.Classes);
-							ClassUpdateInformation res = db.UpdateClassInformation (resolved, fileName);
+							ClassUpdateInformation res = db.UpdateFromParseInfo (parseInformation, fileName);
 							NotifyParseInfoChange (fileName, res);
 						}
 						lastUpdateSize[fileName] = text.GetHashCode();
@@ -573,9 +639,17 @@
 
 		public IClass GetClass (IProject project, string typeName)
 		{
-			return GetClass(project, typeName, true);
+			return GetClass(project, typeName, false, true);
 		}
 		
+		public IClass GetClass (IProject project, string typeName, bool deepSearchReferences, bool caseSensitive)
+		{
+			if (deepSearchReferences)
+				return DeepGetClass (project, typeName, caseSensitive);
+			else
+				return GetClass (project, typeName, caseSensitive);
+		}
+		
 		public IClass GetClass (IProject project, string typeName, bool caseSensitive)
 		{
 			CodeCompletionDatabase db = GetProjectDatabase (project);
@@ -595,6 +669,36 @@
 			return db.GetClass (typeName, caseSensitive);
 		}
 		
+		public IClass DeepGetClass (IProject project, string typeName, bool caseSensitive)
+		{
+			ArrayList visited = new ArrayList ();
+			IClass c = DeepGetClassRec (visited, GetProjectDatabase (project), typeName, caseSensitive);
+			if (c != null) return c;
+
+			CodeCompletionDatabase db = GetDatabase (CoreDB);
+			return db.GetClass (typeName, caseSensitive);
+		}
+		
+		internal IClass DeepGetClassRec (ArrayList visitedDbs, CodeCompletionDatabase db, string typeName, bool caseSensitive)
+		{
+			if (db == null) return null;
+			if (visitedDbs.Contains (db)) return null;
+			
+			visitedDbs.Add (db);
+			
+			IClass c = db.GetClass (typeName, caseSensitive);
+			if (c != null) return c;
+			
+			foreach (ReferenceEntry re in db.References)
+			{
+				CodeCompletionDatabase cdb = GetDatabase (re.Uri);
+				if (cdb == null) continue;
+				c = DeepGetClassRec (visitedDbs, cdb, typeName, caseSensitive);
+				if (c != null) return c;
+			}
+			return null;
+		}
+		
 		public string[] GetNamespaceList (IProject project, string subNameSpace)
 		{
 			return GetNamespaceList (project, subNameSpace, true);
@@ -746,14 +850,19 @@
 			}
 			string fullname = callingClass.FullyQualifiedName;
 			string[] namespaces = fullname.Split(new char[] {'.'});
-			string curnamespace = namespaces[0] + '.';
-			for (int i = 1; i < namespaces.Length; ++i) {
+			string curnamespace = "";
+			int i = 0;
+			
+			do {
+				curnamespace += namespaces[i] + '.';
 				c = GetClass(project, curnamespace + name);
 				if (c != null) {
 					return c;
 				}
-				curnamespace += namespaces[i] + '.';
+				i++;
 			}
+			while (i < namespaces.Length);
+			
 			return null;
 		}
 		
@@ -819,17 +928,20 @@
 			return null;
 		}
 		
-		public ClassCollection ResolveTypes (IProject project, ICompilationUnit unit, ClassCollection types)
+		public bool ResolveTypes (IProject project, ICompilationUnit unit, ClassCollection types, out ClassCollection result)
 		{
 			CompilationUnitTypeResolver tr = new CompilationUnitTypeResolver (project, unit, this);
 			
-			ClassCollection col = new ClassCollection ();
+			bool allResolved = true;
+			result = new ClassCollection ();
 			foreach (IClass c in types) {
 				tr.CallingClass = c;
-				col.Add (PersistentClass.Resolve (c, tr));
+				tr.AllResolved = true;
+				result.Add (PersistentClass.Resolve (c, tr));
+				allResolved = allResolved && tr.AllResolved;
 			}
 				
-			return col;
+			return allResolved;
 		}
 		
 		public IEnumerable GetClassInheritanceTree (IProject project, IClass cls)
@@ -851,7 +963,6 @@
 		
 		public IParseInformation DoParseFile (string fileName, string fileContent)
 		{
-			Console.WriteLine ("PARSING " + fileName);
 			IParser parser = GetParser(fileName);
 			
 			if (parser == null) {
@@ -1094,13 +1205,13 @@
 	
 	public class ClassInheritanceEnumerator : IEnumerator, IEnumerable
 	{
-		IParserService parserService;
+		DefaultParserService parserService;
 		IClass topLevelClass;
 		IClass currentClass  = null;
 		Queue  baseTypeQueue = new Queue();
 		IProject project;
 
-		public ClassInheritanceEnumerator(IParserService parserService, IProject project, IClass topLevelClass)
+		internal ClassInheritanceEnumerator(DefaultParserService parserService, IProject project, IClass topLevelClass)
 		{
 			this.parserService = parserService;
 			this.project = project;
@@ -1116,9 +1227,8 @@
 
 		void PutBaseClassesOnStack(IClass c)
 		{
-			foreach (string baseTypeName in c.BaseTypes) {
+			foreach (string baseTypeName in c.BaseTypes)
 				baseTypeQueue.Enqueue(baseTypeName);
-			}
 		}
 
 		public IClass Current {
@@ -1140,7 +1250,7 @@
 			}
 			string baseTypeName = baseTypeQueue.Dequeue().ToString();
 
-			IClass baseType = parserService.GetClass(project, baseTypeName);
+			IClass baseType = parserService.DeepGetClass (project, baseTypeName, true);
 			if (baseType == null) {
 				ICompilationUnit unit = currentClass == null ? null : currentClass.CompilationUnit;
 				if (unit != null) {
@@ -1157,7 +1267,7 @@
 				currentClass = baseType;
 				PutBaseClassesOnStack(currentClass);
 			}
-
+			
 			return baseType != null;
 		}
 

Modified: trunk/MonoDevelop/src/Main/Base/Services/ParserService/IParserService.cs
===================================================================
--- trunk/MonoDevelop/src/Main/Base/Services/ParserService/IParserService.cs	2004-05-30 05:30:41 UTC (rev 1666)
+++ trunk/MonoDevelop/src/Main/Base/Services/ParserService/IParserService.cs	2004-05-30 18:19:41 UTC (rev 1667)
@@ -55,7 +55,7 @@
 		string    SearchNamespace(IProject project, IUsing iusing, string partitialNamespaceName);
 		IClass    SearchType(IProject project, IUsing iusing, string partitialTypeName);
 		
-		IClass    GetClass(IProject project, string typeName, bool caseSensitive);
+		IClass    GetClass(IProject project, string typeName, bool deepSearchReferences, bool caseSensitive);
 		string[]  GetNamespaceList(IProject project, string subNameSpace, bool caseSensitive);
 		ArrayList GetNamespaceContents(IProject project, string subNameSpace, bool includeReferences, bool caseSensitive);
 		bool      NamespaceExists(IProject project, string name, bool caseSensitive);




More information about the Monodevelop-patches-list mailing list