private bool DoLeftHidesRight(MethodReference left, MethodReference right) { DBC.Assert(left.Name == right.Name, "names don't match"); bool hides = false; if (left.Parameters.Count == right.Parameters.Count) { int count = 0; for (int i = 0; i < left.Parameters.Count && count >= 0; ++i) { TypeReference leftType = left.Parameters[i].ParameterType; TypeReference rightType = right.Parameters[i].ParameterType; if (leftType.MetadataToken != rightType.MetadataToken) { if (rightType.IsSubclassOf(leftType, Cache)) { ++count; } else { count = -1; // left types have to all be equal or a base class of right } } } hides = count > 0; } return(hides); }
public void VisitBegin(BeginType begin) { DBC.Assert(!m_checkingCalls, "VisitBegin was called after we started visiting calls"); // If the class is internal, if (begin.Type.IsNotPublic || begin.Type.IsNestedAssembly || begin.Type.IsNestedFamilyAndAssembly) { Log.DebugLine(this, "-----------------------------------"); Log.DebugLine(this, "{0}", begin.Type); // and it directly implements one or more public interfaces, int count = DoCountInterfaces(begin.Type); if (count > 0) { // then build a list of all the non-private/protected methods // in the class that were not declared in an interface. foreach (MethodDefinition method in begin.Type.Methods) { if (!method.IsPrivate && !method.IsFamily) { if (!method.IsConstructor) { TypeReference t = method.GetDeclaredIn(Cache); if (t == begin.Type) { Log.DebugLine(this, " adding {0}", method.Name); m_candidates.Add(method, new Info(begin.Type)); } } } } } } }
public static string ColorizeCode(string code) { string result = ms_codeRE.Replace(code, match => { if (match.Groups[1].Length > 0) { return("<span class = \"comment\">" + match.Groups[1].Value + "</span>"); } else if (match.Groups[2].Length > 0) { return("<span class = \"string\">" + match.Groups[2].Value + "</span>"); } DBC.Assert(match.Groups[3].Length > 0, "expected a keyword match"); if (Array.IndexOf(ms_keywords, match.Groups[3].Value) >= 0) { return("<span class = \"keyword\">" + match.Groups[3].Value + "</span>"); } else { return(match.Groups[3].Value); } }); return(result); }
private bool DoMatches(int base1, int base2, int count) { DBC.Assert(count >= 0, "count is negative ({0})", count); bool match = true; Log.DebugLine(this, "checking {0} instructions at {1:X2} and {2:X2}", count, m_info.Instructions[base1].Untyped.Offset, m_info.Instructions[base2].Untyped.Offset); for (int i = 0; i < count && match; ++i) { Instruction i1 = m_info.Instructions[base1 + i].Untyped; Instruction i2 = m_info.Instructions[base2 + i].Untyped; if (!i1.Matches(i2)) { match = false; Log.DebugLine(this, " {0} != {1}", m_info.Instructions[base1 + i], m_info.Instructions[base2 + i]); } } if (match) { Log.DebugLine(this, " matches"); } return(match); }
/// <summary>Check an assembly and return an array of violations.</summary> /// <remarks>OnlyType is used to check only the types that contain a string in the array which may be null. /// Severity is the minimum rule severity to use. IgnoreBreaks is true if we want to /// ignore rules that break binary compatibility. Note that this should only be called once: /// if you want to smoke multiple assemblies create a new AnalyzeAssembly object.</remarks> public Error[] Analyze(string imagePath, string[] onlyType, Severity severity, bool ignoreBreaks) { DBC.Assert(!m_analyzed, "Analyze can only be called once"); // TODO: would be nice to relax this, maybe add an overload to allow another assembly to be checked with the same settings m_analyzed = true; Profile.Start("AssemblyFactory"); AssemblyDefinition assemblyDef = AssemblyFactory.GetAssembly(imagePath); Profile.Stop("AssemblyFactory"); string path = Path.GetFullPath(imagePath); // need to add a cecil search directory so that it finds assemblies in the same directory as the assembly we're checking string dir = Path.GetDirectoryName(path); BaseAssemblyResolver resolver = assemblyDef.Resolver as BaseAssemblyResolver; DBC.Assert(resolver != null, "assemblyDef.Resolver isn't a BaseAssemblyResolver"); resolver.AddSearchDirectory(dir); m_symbols = new SymbolTable(); AssemblyCache cache = new AssemblyCache(m_symbols, assemblyDef, m_callback); var assembly = System.Reflection.Assembly.GetExecutingAssembly(); m_checker.LoadRules(assembly, cache, severity, ignoreBreaks); Error[] errors = DoCheckAssembly(assemblyDef, cache, onlyType); return(errors); }
private TypeReference DoConsolidateTypes(List <TypeReference> types) { DBC.Assert(types.Count > 1, "can only consolidate multiple types"); TypeReference current = types[0]; return(DoConsolidateTypes(types, current, 1)); }
public void Init(AssemblyCache cache, List <Error> errors) { DBC.Assert(cache != null, "cache is null"); DBC.Assert(errors != null, "errors is null"); m_cache = cache; m_errors = errors; }
public void VisitInitObj(InitObj init) { DBC.Assert(m_state == State.Calls, "state is {0}", m_state); if (m_types.Count > 0) { DoRemoveTypes(init.Type); } }
public void VisitNewObj(NewObj newobj) { DBC.Assert(m_state == State.Calls, "state is {0}", m_state); if (m_types.Count > 0) { DoRemoveTypes(newobj.Ctor.DeclaringType); } }
private void DoSanityTest() { foreach (Option option in m_options.Values) { foreach (string name in option.Names) { Option result = DoFind(name); // make sure no two options are ambiguous DBC.Assert(result != null, "expected to find {0}", name); } } }
public void LoadRules(System.Reflection.Assembly assembly, AssemblyCache cache, Severity severity, bool ignoreBreaks) { DBC.Assert(cache != null, "cache is null"); Profile.Start("LoadRules"); int count = DoLoadRules(assembly, cache, severity, ignoreBreaks); DoCheckXml(); count += DoLoadCustomRules(cache, severity, ignoreBreaks); Profile.Stop("LoadRules"); Log.InfoLine(this, "loaded {0} rules (although not all may be used)", count); }
// call System.Void Smokey.Tests.NotInstantiatedTest/Tuple2`2<T0,T1>::.ctor(T0,T1) public void VisitCall(Call call) { DBC.Assert(m_state == State.Calls, "state is {0}", m_state); if (m_types.Count > 0) { MethodInfo info = Cache.FindMethod(call.Target); if (info != null && info.Method.IsConstructor) { DoRemoveTypes(info.Method.DeclaringType); } } }
public void VisitEndTypes(EndTypes end) { Unused.Value = end; DBC.Assert(m_state == State.Types, "state is {0}", m_state); Log.DebugLine(this, "-------------"); Log.DebugLine(this, "VisitEndTypes"); m_types.AddRange(m_keys.Select(k => k.Type.FullName)); m_types.Sort(); m_state = State.Calls; }
private static long?[] DoMeetVars(long?[] lhs, long?[] rhs) { DBC.Assert(lhs.Length == rhs.Length, "lengths don't match"); long?[] result = new long?[lhs.Length]; for (int i = 0; i < lhs.Length; ++i) { result[i] = DoMeet(lhs[i], rhs[i]); } return(result); }
private void DoGetMethods(AssemblyDefinition assembly, List <MethodInfo> methods, string[] names, bool allowEmpty) { string testName = GetType().FullName; DBC.Assert(names.Distinct().Count() == names.Length, "duplicate name in " + string.Join(", ", names)); foreach (string name in names) { string[] parts = name.Split('.'); DBC.Assert(parts.Length == 2, "{0} should be of the form 'test.method'", name); string caseType = parts[0]; string fullName = string.Format("{0}/{1}", testName, caseType); TypeDefinition type = assembly.MainModule.Types[fullName]; DBC.Assert(type != null, "null type from {0}", fullName); string caseMethod = parts[1]; if (caseMethod.Length > 0) { if (caseMethod == caseType) { DBC.Assert(type.Constructors.Count > 0, "expected a ctor, but {0} has no ctors", caseType); foreach (MethodDefinition method in type.Constructors) { methods.Add(new MethodInfo(type, method)); } } else { MethodDefinition[] defs = type.Methods.GetMethod(caseMethod); DBC.Assert(defs.Length == 1, "expected 1 method, but {0} has {1} methods", caseType + "::" + caseMethod, defs.Length); methods.Add(new MethodInfo(type, defs[0])); } } else { DBC.Assert(allowEmpty, "{0} needs a method name", name); foreach (MethodDefinition method in type.Constructors) { methods.Add(new MethodInfo(type, method)); } foreach (MethodDefinition method in type.Methods) { methods.Add(new MethodInfo(type, method)); } } } }
private TypeReference DoConsolidateTypes(List <TypeReference> types, TypeReference current, int i) { DBC.Assert(i > 0, "can't have current with zero index"); DBC.Assert(i < types.Count, "i is out of range"); TypeReference result = current.CommonClass(types[i], Cache); if (i + 1 < types.Count && result != null) { result = DoConsolidateTypes(types, result, i + 1); } return(result); }
// This is visited after methods. public void VisitFini(EndTesting end) { Unused.Value = end; DBC.Assert(m_state == State.Calls, "state is {0}", m_state); m_state = State.End; if (m_types.Count > 0) { string details = "Unused: " + string.Join(Environment.NewLine, m_types.ToArray()); Log.DebugLine(this, details); Reporter.AssemblyFailed(Cache.Assembly, CheckID, details); } }
private void DoGetUsed(AssemblyDefinition assembly, List <TypeDefinition> types, string[] names) { string testName = GetType().FullName; foreach (string name in names) { DBC.Assert(name.IndexOf('.') < 0, "{0} has a method", name); string fullName = string.Format("{0}/{1}", testName, name); TypeDefinition type = assembly.MainModule.Types[fullName]; DBC.Assert(type != null, "Couldn't find {0}", fullName); types.Add(type); } }
// Returns the smallest number k such that the instructions in // [offset - k, offset] push a single value onto the stack. private int DoGetPushRange(MethodInfo info, int offset) { int delta = DoGetStackDelta(info.Instructions[offset]); int k = 0; while (delta <= 0 && offset - k >= 0) { ++k; delta += DoGetStackDelta(info.Instructions[offset - k]); } DBC.Assert(offset - k >= 0, "couldn't find the range"); return(k); }
// Note that using reflection is roughly 6x faster than using a thunk. // It'd be slicker to register the methods via attributes but that would // be quite a bit slower... public void Register <T>(T rule, string method) where T : Rule { #if DEBUG Rule r; if (m_registered.TryGetValue(rule.CheckID, out r)) { DBC.Assert(rule.Equals(r), "multiple rules have id {0}", rule.CheckID); } else { m_registered.Add(rule.CheckID, rule); } #endif Register(rule, method, rule.GetType().Name, rule.CheckID); }
public void VisitType(TypeDefinition type) { DBC.Assert(m_state == State.Types, "state is {0}", m_state); Log.DebugLine(this, "{0}", type.FullName); if (!type.ExternallyVisible(Cache) && DoInstantiable(type) && DoValidType(type)) { if (!type.IsCompilerGenerated()) { var key = new AssemblyCache.TypeKey(type); DBC.Assert(m_keys.IndexOf(key) < 0, "{0} is already in types", type.FullName); Log.DebugLine(this, "adding {0}", type.FullName); m_keys.Add(key); } } }
public void TypeFailed(TypeDefinition type, string checkID, string details) { if (!type.CustomAttributes.HasDisableRule(checkID)) { DBC.Assert(m_cache != null, "m_cache is null"); DBC.Assert(m_cache.Symbols != null, "m_cache.Symbols is null"); DBC.Assert(type != null, "type is null"); DBC.Assert(details != null, "details is null"); Location location = m_cache.Symbols.Location(type, details); Violation violation = ViolationDatabase.Get(checkID); DBC.Assert(violation != null, "violation is null"); DBC.Assert(m_errors != null, "m_errors is null"); m_errors.Add(new Error(location, violation)); } }
private static void DoViolation(XmlNode violation) { string checkID = violation.Attributes["checkID"].Value; Severity severity = (Severity)Enum.Parse(typeof(Severity), violation.Attributes["severity"].Value); bool breaking = violation.Attributes["breaking"].Value.ToLower() == "true"; foreach (XmlNode child in violation.ChildNodes) { if (child.Name == "Translation") { // Get the next translation. Entry entry = DoTranslation(child, checkID, severity, breaking); #if DEBUG // Make sure it's not a duplicate of one we've seen already. string key = string.Format("{0}/{1}", checkID, entry.Lang); int i = ms_checkIDs.BinarySearch(key); if (i < 0) { ms_checkIDs.Insert(~i, key); } else { DBC.Assert(false, "{0} is already defined", key); } #endif // If the checkID is new, or the language is better than // our current translation use the new translation. int index = ms_entries.BinarySearch(entry); if (index < 0) { Log.DebugLine(true, "adding {0}", checkID); ms_entries.Insert(~index, entry); } else if (DoLeftIsBetter(entry, ms_entries[index])) { Log.DebugLine(true, "overriding {0} ({1} is better than {2})", checkID, entry.Lang, ms_entries[index].Lang); ms_entries[index] = entry; } } } }
/// <summary>Split the string based on capitalization changes.</summary> /// <remarks>So, "inName" becomes ["in", "Name"].</remarks> public static string[] CapsSplit(this string str) { DBC.Pre(str != null, "str is null"); List <string> parts = new List <string>(); int index = 0; while (index < str.Length) { int count = DoFindCapsRun(str, index); DBC.Assert(count > 0, "count is {0}", count); parts.Add(str.Substring(index, count)); index += count; } return(parts.ToArray()); }
private Option DoFind(string arg) { DBC.Assert(!string.IsNullOrEmpty(arg), "null or empty arg"); Option result = null; int best = -1; List <string> matches = new List <string>(); foreach (Option option in m_options.Values) { string alias; int num = option.Match(arg, out alias); if (num > 0 && num >= best) { if (num > best) { best = num; matches.Clear(); } result = option; matches.Add(alias); } } if (result == null) { throw new MalformedCommandLineException(arg + " is not a valid option"); } if (matches.Count > 1) { string mesg = string.Format("{0} matches the {1} options", arg, string.Join(", ", matches.ToArray())); throw new MalformedCommandLineException(mesg); } return(result); }
private Dictionary <int, BasicBlock> DoGetUnwiredBlocks(TypedInstructionCollection instructions) { // First get a list of all the instructions which start a block. List <int> leaders = DoGetLeaders(instructions); // Sort them so we can efficiently pop them off the list. leaders.Sort(); Log.TraceLine(this, "Leaders: {0}", DoTargetsToString(instructions, leaders)); leaders.Reverse(); // And form the basic blocks by starting at the first leader and // accumulating instructions until we hit another leader. Dictionary <int, BasicBlock> blocks = new Dictionary <int, BasicBlock>(); while (leaders.Count > 0) { int first = leaders[leaders.Count - 1]; leaders.RemoveAt(leaders.Count - 1); BasicBlock block; if (leaders.Count > 0) { int last = leaders[leaders.Count - 1]; DBC.Assert(first < last, "Leader {0} should be before {1}", first, last); block = new BasicBlock(instructions[first], instructions[last - 1]); } else { block = new BasicBlock(instructions[first], instructions[instructions.Length - 1]); } blocks.Add(first, block); Log.DebugLine(this, "Added block: {0}", block); } return(blocks); }
private void DoGetTypes(List <List <TypeDefinition> > types, string[] names) { DBC.Assert(names.Distinct().Count() == names.Length, "duplicate name in " + string.Join(", ", names)); string testName = GetType().FullName; foreach (string composed in names) { string[] compose = composed.Split('+'); List <TypeDefinition> inner = new List <TypeDefinition>(); foreach (string name in compose) { string fullName = string.Format("{0}/{1}", testName, name); TypeDefinition type = Assembly.MainModule.Types[fullName]; DBC.Assert(type != null, "Couldn't find {0}", fullName); inner.Add(type); } types.Add(inner); } }
private void DoGetEvents(AssemblyDefinition assembly, List <EventDefinition> events, string[] names) { string testName = GetType().FullName; foreach (string name in names) { string[] parts = name.Split('.'); DBC.Assert(parts.Length == 2, "{0} should be of the form 'test.event'", name); string caseType = parts[0]; string fullName = string.Format("{0}/{1}", testName, caseType); TypeDefinition type = assembly.MainModule.Types[fullName]; DBC.Assert(type != null, "null type from {0}", fullName); string caseEvent = parts[1]; DBC.Assert(caseEvent.Length > 0, "{0} has no event part", name); EventDefinition evt = type.Events.GetEvent(caseEvent); DBC.Assert(evt != null, "couldn't find an event for {0}", caseType + "::" + caseEvent); events.Add(evt); } }
public void VisitField(FieldDefinition field) { if (m_needsCheck && field.IsAssembly && m_type.IsClass) // if (m_needsCheck && field.IsAssembly && m_type.IsClass && !m_type.FullName.Contains("PrivateImplementationDetails")) { if (!m_type.CustomAttributes.HasDisableRule("D1050")) { TypeAttributes attrs = m_type.Attributes; if (!m_type.IsValueType || (attrs & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout) { if (m_fields.ContainsKey(field)) { DBC.Assert(m_fields[field] == State.Referenced, "state is {0}", m_fields[field]); m_fields[field] = State.Used; } else { m_fields.Add(field, State.Defined); } } } } }
[DisableRule("D1042", "IdenticalMethods")] // TODO: should have a base class for progress and watchdog public void Shutdown() { if (m_disposed) { throw new ObjectDisposedException(GetType().Name); } lock (m_lock) { if (m_running) { m_running = false; Monitor.PulseAll(m_lock); } } if (m_thread != null) { bool terminated = m_thread.Join(1000); DBC.Assert(terminated, "thread didn't terminate"); m_thread = null; } }