public static string IsTypeMovedToNamespaceError(CompilationUnit cu, int line, int column) { var self = new InvalidTypeOrNamespaceErrorTypeMapper(line, column); cu.AcceptVisitor(self, null); return(self.Found); }
// C# compiler does not emmit the full qualified type name when it fails to resolve a 'theorically', fully qualified type reference // for instance, if 'NSBar', a namespace gets renamed to 'NSBar2', a refernce to 'NSFoo.NSBar.TypeBaz' will emit an error // with only NSBar and NSFoo in the message. In this case we use NRefactory to dive in to the code, looking for type references // in the reported error line/column private static Type FindTypeMatchingMovedTypeBasedOnNamespaceFromError(IEnumerable <string> lines) { var value = GetValueFromNormalizedMessage(lines, "Line="); var line = (value != null) ? Int32.Parse(value) : -1; value = GetValueFromNormalizedMessage(lines, "Column="); var column = (value != null) ? Int32.Parse(value) : -1; var script = GetValueFromNormalizedMessage(lines, "Script="); if (line == -1 || column == -1 || script == null) { return(null); } try { using (var scriptStream = File.Open(script, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var parser = ParserFactory.CreateParser(ICSharpCode.NRefactory.SupportedLanguage.CSharp, new StreamReader(scriptStream)); parser.Lexer.EvaluateConditionalCompilation = false; parser.Parse(); var typeNotFound = InvalidTypeOrNamespaceErrorTypeMapper.IsTypeMovedToNamespaceError(parser.CompilationUnit, line, column); if (typeNotFound == null) { return(null); } return(FindExactTypeMatchingMovedType(typeNotFound)); } } catch (FileNotFoundException) { return(null); } }
// C# compiler does not emit the full qualified type name when it fails to resolve a 'theoretically', fully qualified type reference // for instance, if 'NSBar', a namespace gets renamed to 'NSBar2', a reference to 'NSFoo.NSBar.TypeBaz' will emit an error // with only NSBar and NSFoo in the message. In this case we use NRefactory to dive in to the code, looking for type references // in the reported error line/column static Type FindTypeMatchingMovedTypeBasedOnNamespaceFromError(IEnumerable <string> lines) { var value = GetValueFromNormalizedMessage(lines, "Line="); var line = (value != null) ? Int32.Parse(value) : -1; value = GetValueFromNormalizedMessage(lines, "Column="); var column = (value != null) ? Int32.Parse(value) : -1; var script = GetValueFromNormalizedMessage(lines, "Script="); if (line == -1 || column == -1 || script == null) { return(null); } var entityName = GetValueFromNormalizedMessage(lines, "EntityName="); try { using (var scriptStream = File.Open(script, System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { var parser = ParserFactory.CreateParser(ICSharpCode.NRefactory.SupportedLanguage.CSharp, new StreamReader(scriptStream)); parser.Lexer.EvaluateConditionalCompilation = false; parser.Parse(); var self = new InvalidTypeOrNamespaceErrorTypeMapper(line, column, entityName); parser.CompilationUnit.AcceptVisitor(self, null); if (self.identifiers.Count == 0) { return(null); } var availableTypes = TypeCache.GetTypesWithAttribute(typeof(MovedFromAttribute)); foreach (var ns in self.NamespacesInScope) { foreach (var i in self.identifiers) { foreach (var t in availableTypes) { var @namespace = ns; foreach (var part in i.parts) { //If the usage + any of the candidate namespaces matches a real type, this usage is valid and does not need to be updated //this is required to avoid false positives when a type that exists on *editor* (and is marked as moved) is used in a platform that //does not support it. If we don't check the namespaces in scope we'll flag this as an error due to the type being moved (and //whence, trigger the updater, whereas the real problem is that the type is not supported in the platform (see issue #96123) //whence this is indeed a programing error that the user needs to fix. if (t.Name == part && t.Namespace == @namespace) { return(null); } if (t.Name == part && NamespaceHasChanged(t, @namespace)) { return(t); } if (string.IsNullOrEmpty(@namespace)) { @namespace = part; } else { @namespace = @namespace + "." + part; } } } } } return(null); } } catch (FileNotFoundException) { return(null); } }
// C# compiler does not emmit the full qualified type name when it fails to resolve a 'theorically', fully qualified type reference // for instance, if 'NSBar', a namespace gets renamed to 'NSBar2', a refernce to 'NSFoo.NSBar.TypeBaz' will emit an error // with only NSBar and NSFoo in the message. In this case we use NRefactory to dive in to the code, looking for type references // in the reported error line/column private static Type FindTypeMatchingMovedTypeBasedOnNamespaceFromError(IEnumerable <string> lines) { var value = GetValueFromNormalizedMessage(lines, "Line="); var line = (value != null) ? Int32.Parse(value) : -1; value = GetValueFromNormalizedMessage(lines, "Column="); var column = (value != null) ? Int32.Parse(value) : -1; var script = GetValueFromNormalizedMessage(lines, "Script="); if (line == -1 || column == -1 || script == null) { return(null); } try { using (var scriptStream = File.Open(script, System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { var parser = ParserFactory.CreateParser(ICSharpCode.NRefactory.SupportedLanguage.CSharp, new StreamReader(scriptStream)); parser.Lexer.EvaluateConditionalCompilation = false; parser.Parse(); var self = new InvalidTypeOrNamespaceErrorTypeMapper(line, column); parser.CompilationUnit.AcceptVisitor(self, null); if (self.identifierParts.Count == 0) { return(null); } List <string> candidateNamespaces = new List <string>(self.usings.Where(u => !u.IsAlias).Select(u => u.Name)); List <Identifier> candidateFullyQualifiedNames = candidateNamespaces.Select(ns => new Identifier { @namespace = ns, name = self.identifierParts[0] }).ToList(); string @namespace = string.Empty; foreach (var identifier in self.identifierParts) { candidateFullyQualifiedNames.Add(new Identifier { name = identifier, @namespace = @namespace }); if (@namespace != string.Empty) { @namespace += "."; } @namespace += identifier; } //If the usage + any of the candidate namespaces matches a real type, this usage is valid and does not need to be updated if (FindTypeInLoadedAssemblies(t => candidateFullyQualifiedNames.Contains(new Identifier { name = t.Name, @namespace = t.Namespace })) != null) { return(null); } return(FindTypeInLoadedAssemblies(t => candidateFullyQualifiedNames.Any(id => id.name == t.Name && NamespaceHasChanged(t, id.@namespace)))); } } catch (FileNotFoundException) { return(null); } }