static IEnumerable <DModule> TryGetGenericImportingPackageForSymbol(DNode nodeToTestImportabilityFor) { if (nodeToTestImportabilityFor == null) { yield break; } var moduleContainingPackage = GlobalParseCache.GetPackage(nodeToTestImportabilityFor.NodeRoot as DModule); while (moduleContainingPackage != null) { // Search for package.d-Modules; var packageModule = (moduleContainingPackage.Parent ?? moduleContainingPackage).GetModule(moduleContainingPackage.NameHash); if (packageModule == null) { moduleContainingPackage = moduleContainingPackage.Parent; continue; } // Try to get from found package module to destination node var ctxt = new ResolutionContext(new LegacyParseCacheView(new[] { moduleContainingPackage.Root }), null, packageModule); ctxt.CurrentContext.ContextDependentOptions = ResolutionOptions.ReturnMethodReferencesOnly | ResolutionOptions.DontResolveBaseTypes; var td = D_Parser.Parser.DParser.ParseBasicType(DNode.GetNodePath(nodeToTestImportabilityFor, true)); var res = TypeDeclarationResolver.ResolveSingle(td, ctxt, false); foreach (var ov in AmbiguousType.TryDissolve(res)) { if (ov is DSymbol && (ov as DSymbol).Definition == nodeToTestImportabilityFor) { yield return(packageModule); break; } } moduleContainingPackage = moduleContainingPackage.Parent; } }
public override ParsedDocument Parse(bool storeAst, string file, TextReader content, Project prj = null) { if (!storeAst) { return(null); } ProjectFile pf = null; if (prj == null) { var sln = Ide.IdeApp.ProjectOperations.CurrentSelectedSolution; if (sln != null) { foreach (var proj in sln.GetAllProjects()) { if (proj.IsFileInProject(file)) { prj = proj; pf = proj.GetProjectFile(file); break; } } } } else if (prj.IsFileInProject(file)) { pf = prj.GetProjectFile(file); } // HACK(?) The folds are parsed before the document gets loaded // - so reuse the last parsed document to save time // -- What if multiple docs are opened? if (LastParsedMod is ParsedDModule && LastParsedMod.FileName == file) { var d = LastParsedMod as ParsedDModule; LastParsedMod = null; return(d); } else { LastParsedMod = null; } var dprj = prj as AbstractDProject; // Remove obsolete ast from cache GlobalParseCache.RemoveModule(file); DModule ast; var doc = new ParsedDModule(file); var parser = DParser.Create(content); // Also put attention on non-ddoc comments; These will be used to generate foldable comment regions then parser.Lexer.OnlyEnlistDDocComments = false; // Parse the code try { ast = parser.Parse(); } catch (TooManyErrorsException x) { ast = parser.Document; } // Update project owner information / Build appropriate module name if (string.IsNullOrEmpty(ast.ModuleName)) { if (pf == null) { ast.ModuleName = Path.GetFileNameWithoutExtension(file); } else { ast.ModuleName = BuildModuleName(pf); } } ast.FileName = file; // Assign new ast to the ParsedDDocument object doc.DDom = ast; // Add parser errors to the parser output foreach (var parserError in parser.ParseErrors) { doc.ErrorList.Add(new Error( ErrorType.Error, parserError.Message, parserError.Location.Line, parserError.Location.Column)); } #region Provide comment fold support by addin them to the IDE document object foreach (var cm in parser.TrackerVariables.Comments) { var c = new MonoDevelop.Ide.TypeSystem.Comment(cm.CommentText) { CommentStartsLine = cm.CommentStartsLine, CommentType = (cm.CommentType & D_Parser.Parser.Comment.Type.Block) != 0 ? CommentType.Block : CommentType.SingleLine, IsDocumentation = cm.CommentType.HasFlag(D_Parser.Parser.Comment.Type.Documentation), }; if (c.CommentType == CommentType.SingleLine) { if (c.IsDocumentation) { c.OpenTag = "///"; } else { c.OpenTag = "//"; } } else { if (c.IsDocumentation) { c.OpenTag = "/**"; c.ClosingTag = "*/"; } else { c.OpenTag = "/*"; c.ClosingTag = "*/"; } } c.Region = new DomRegion(cm.StartPosition.Line, cm.StartPosition.Column, cm.EndPosition.Line, cm.EndPosition.Column); doc.Comments.Add(c); // Enlist TODO/FIXME/HACK etc. stuff in the IDE's project task list for (int i = CommentTag.SpecialCommentTags.Count - 1; i >= 0; i--) { if (c.Text.StartsWith(CommentTag.SpecialCommentTags[i].Tag)) { doc.Add(new Tag(CommentTag.SpecialCommentTags[i].Tag, c.Text, c.Region)); break; } } } #endregion #region Serialize to NRefactory Dom structure /* * var cu = new CompilationUnit(file); * doc.CompilationUnit = cu; * * var global = new DomType(cu, ClassType.Class, * Modifiers.Public | Modifiers.Partial, * "(global)", * new DomLocation(), * ast.ModuleName, * new DomRegion()); * cu.Add(global); * * foreach (var n in ast) * { * var ch = ConvertDParserToDomNode(n, doc); * * if (ch is DomField || ch is DomMethod) * global.Add(ch as IMember); * else * cu.Add(ch as IType); * } */ #endregion if (prj != null) { // Workaround for tags not being displayed var ctnt = TypeSystemService.GetProjectContentWrapper(prj); if (ctnt != null) { var tags = ctnt.GetExtensionObject <ProjectCommentTags>(); if (tags != null) { tags.UpdateTags(prj, file, doc.TagComments); } } } // Update UFCS ModulePackage pack; if ((pack = GlobalParseCache.GetPackage(ast, false)) != null && (pack = pack.Root) != null) { // If the file is not associated with any project, // check if the file is located in an imported/included directory // and update the respective cache. // Note: ParseCache.Remove() also affects the Ufcs cache, // but when adding it again, the UfcsCache has to be updated manually ParseCacheView pcw; bool containsPack = false; if (prj != null) { pcw = dprj.ParseCache; containsPack = true; } else { // Find out which compiler environment fits most pcw = null; foreach (var cmp in DCompilerService.Instance.Compilers) { pcw = cmp.GenParseCacheView(); foreach (var r in pack as IEnumerable <ModulePackage> ) { if (r == pack) { containsPack = true; break; } } if (containsPack) { break; } } } if (containsPack) { (pack as RootPackage).UfcsCache.CacheModuleMethods(ast, new ResolutionContext(pcw, null, ast)); } } return(doc); }