2
// ProjectCodeCompletionDatabase.cs
7
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
using System.Collections;
31
using System.Collections.Generic;
34
using MonoDevelop.Core;
35
using MonoDevelop.Projects;
36
using MonoDevelop.Projects.Dom.Parser;
37
using MonoDevelop.Core.Assemblies;
38
using System.Reflection;
40
namespace MonoDevelop.Projects.Dom.Serialization
42
internal class ProjectCodeCompletionDatabase : SerializationCodeCompletionDatabase
45
bool initialFileCheck;
46
string lastVersion = null;
49
public ProjectCodeCompletionDatabase (Project project, ParserDatabase pdb): base (pdb, true)
51
Counters.LiveProjectDatabases++;
52
this.project = project;
53
SetLocation (project.BaseDirectory, project.Name);
59
project.FileChangedInProject += new ProjectFileEventHandler (OnFileChanged);
60
project.FileAddedToProject += new ProjectFileEventHandler (OnFileAdded);
61
project.FileRemovedFromProject += new ProjectFileEventHandler (OnFileRemoved);
62
project.FileRenamedInProject += new ProjectFileRenamedEventHandler (OnFileRenamed);
63
project.Modified += new SolutionItemModifiedEventHandler (OnProjectModified);
65
initialFileCheck = true;
68
public override Project Project {
69
get { return project; }
72
public override void Dispose ()
74
Counters.LiveProjectDatabases--;
76
project.FileChangedInProject -= new ProjectFileEventHandler (OnFileChanged);
77
project.FileAddedToProject -= new ProjectFileEventHandler (OnFileAdded);
78
project.FileRemovedFromProject -= new ProjectFileEventHandler (OnFileRemoved);
79
project.FileRenamedInProject -= new ProjectFileRenamedEventHandler (OnFileRenamed);
80
project.Modified -= new SolutionItemModifiedEventHandler (OnProjectModified);
83
public override void CheckModifiedFiles ()
85
// Once the first modification check is done, change detection
86
// is done through project events
89
base.CheckModifiedFiles ();
90
initialFileCheck = false;
93
void OnFileChanged (object sender, ProjectFileEventArgs args)
95
FileEntry file = GetFile (args.ProjectFile.Name);
97
file.ParseErrorRetries = 0;
102
void OnFileAdded (object sender, ProjectFileEventArgs args)
104
FileEntry file = AddFile (args.ProjectFile.Name);
105
// CheckModifiedFiles won't detect new files, so parsing
106
// must be manyally signaled
107
QueueParseJob (file);
110
void OnFileRemoved (object sender, ProjectFileEventArgs args)
112
RemoveFile (args.ProjectFile.Name);
115
void OnFileRenamed (object sender, ProjectFileRenamedEventArgs args)
117
RemoveFile (args.OldName);
118
FileEntry file = AddFile (args.NewName);
119
// CheckModifiedFiles won't detect new files, so parsing
120
// must be manyally signaled
121
QueueParseJob (file);
124
void OnProjectModified (object s, SolutionItemModifiedEventArgs args)
126
UpdateCorlibReference ();
127
if (UpdateCorlibReference ())
128
SourceProjectDom.UpdateReferences ();
131
public void UpdateFromProject ()
133
Hashtable fs = new Hashtable ();
134
foreach (ProjectFile file in project.Files)
136
if (GetFile (file.Name) == null) AddFile (file.Name);
137
fs [file.Name] = null;
140
ArrayList keys = new ArrayList ();
141
keys.AddRange (files.Keys);
142
foreach (string file in keys)
144
if (!fs.Contains (file))
149
if (project is DotNetProject) {
150
DotNetProject netProject = (DotNetProject) project;
151
foreach (SolutionItem pr in netProject.GetReferencedItems (ConfigurationSelector.Default)) {
153
string refId = "Project:" + ((Project)pr).FileName;
155
if (!HasReference (refId))
156
AddReference (refId);
160
// Get the assembly references throught the project, since it may have custom references
161
foreach (string file in netProject.GetReferencedAssemblies (ConfigurationSelector.Default, false)) {
162
string refId = "Assembly:" + netProject.TargetRuntime.Id + ":" + Path.GetFullPath (file);
164
if (!HasReference (refId))
165
AddReference (refId);
170
keys.AddRange (references);
171
foreach (ReferenceEntry re in keys)
173
// Don't delete corlib references. They are implicit to projects, but not to pidbs.
174
if (!fs.Contains (re.Uri) && !IsCorlibReference (re))
175
RemoveReference (re.Uri);
177
UpdateCorlibReference ();
180
bool UpdateCorlibReference ()
182
// Creates a reference to the correct version of mscorlib, depending
183
// on the target runtime version. Returns true if the references
186
DotNetProject prj = project as DotNetProject;
187
if (prj == null) return false;
189
if (prj.TargetFramework.Id == lastVersion)
192
// Look for an existing mscorlib reference
193
string currentRefUri = null;
194
foreach (ReferenceEntry re in References) {
195
if (IsCorlibReference (re)) {
196
currentRefUri = re.Uri;
201
// Gets the name and version of the mscorlib assembly required by the project
202
string requiredRefUri = "Assembly:" + prj.TargetRuntime.Id + ":";
203
SystemAssembly asm = prj.TargetRuntime.AssemblyContext.GetAssemblyForVersion (typeof(object).Assembly.FullName, null, prj.TargetFramework);
205
LoggingService.LogWarning ("mscorlib assembly not found for framework '" + prj.TargetFramework.Id + "'. The framework may not be installed.");
208
requiredRefUri += asm.Location;
210
// Replace the old reference if the target version has changed
211
if (currentRefUri != null) {
212
if (currentRefUri != requiredRefUri) {
213
RemoveReference (currentRefUri);
214
AddReference (requiredRefUri);
218
AddReference (requiredRefUri);
224
bool IsCorlibReference (ReferenceEntry re)
229
if (ProjectDomService.ParseAssemblyUri (re.Uri, out tr, out fx, out file))
230
return Path.GetFileNameWithoutExtension (file) == "mscorlib";
235
protected override void ParseFile (string fileName, IProgressMonitor monitor)
237
if (monitor != null) monitor.BeginTask (string.Format (GettextCatalog.GetString ("Parsing file: {0}"), Path.GetFileName (fileName)), 1);
240
ProjectDomService.Parse (this.project,
243
delegate () { return File.ReadAllText (fileName); });
244
// The call to ProjectDomService.Parse will call UpdateFromParseInfo when done
246
if (monitor != null) monitor.EndTask ();
250
int totalUnresolvedCount;
252
public TypeUpdateInformation UpdateFromParseInfo (ICompilationUnit parserInfo, string fileName)
255
ICompilationUnit cu = parserInfo;
257
List<IType> resolved;
259
int unresolvedCount = ResolveTypes (cu, cu.Types, out resolved);
260
totalUnresolvedCount += unresolvedCount;
262
TypeUpdateInformation res = UpdateTypeInformation (resolved, parserInfo.FileName);
264
FileEntry file = files [fileName] as FileEntry;
266
if (unresolvedCount > 0) {
267
if (file.ParseErrorRetries != 1) {
268
file.ParseErrorRetries = 1;
270
// Enqueue the file for quickly reparse. Types can't be resolved most probably because
271
// the file that implements them is not yet parsed.
272
ProjectDomService.QueueParseJob (SourceProjectDom,
273
delegate { UpdateFromParseInfo (parserInfo, fileName); },
278
file.ParseErrorRetries = 0;
282
if ((++parseCount % MAX_ACTIVE_COUNT) == 0)
288
protected override void OnFileRemoved (string fileName, TypeUpdateInformation classInfo)
290
if (classInfo.Removed.Count > 0)
291
ProjectDomService.NotifyTypeUpdate (project, fileName, classInfo);
294
protected internal override void ForceUpdateBROKEN ()
297
totalUnresolvedCount = int.MaxValue;
300
// Keep trying updating the db while types are being resolved
301
lastCount = totalUnresolvedCount;
302
totalUnresolvedCount = 0;
303
base.ForceUpdateBROKEN ();
305
while (totalUnresolvedCount != 0 && totalUnresolvedCount < lastCount);