/// <summary> /// Checks whether any previously uncovered locations are covered in this new run /// </summary> internal void CheckForNewlyCoveredLocations() { foreach (var fss in this.FactorySuggestionsDictionary.Values) { foreach (var pucls in fss.locationStoreSpecificSequences.Values) { if (pucls.IsDormat()) { continue; } if (!pucls.AlreadyCovered && this.IsPrevUncoveredLocationCovered(pucls)) { //this.Log.LogMessage("debug", "Covered the location: " + pucls.CodeLocation.ToString()); //StringBuilder sb = new StringBuilder(); //foreach (Method m in this.LastExecutedMethodCallSequence) //{ // sb.Append(m.ToString() + "\n"); //} //this.Log.LogMessage("debug", "Sequence recorded: " + sb.ToString()); pucls.HitSequence = new MethodSignatureSequence(); foreach (Method m in this.LastExecutedFactoryMethodCallSequence) { pucls.HitSequence.Sequence.Add(MethodOrFieldAnalyzer.GetMethodSignature(m)); } pucls.AlreadyCovered = true; } } } }
/// <summary> /// Includes filtering of the methods based on desired format /// </summary> /// <returns></returns> public bool TryGetFilteredWriteMethods(Field field, TypeEx declaringType, FieldModificationType desiredfmt, out SafeSet <Method> writeMethods) { //Check in the predefined store before proceeding if (PreDefinedMethodEffects.TryGetWriteMethods(this, field, desiredfmt, out writeMethods)) { SafeSet <Method> newWriteMethods = new SafeSet <Method>(); GetCallingMethods(field, declaringType, writeMethods, newWriteMethods); //Filter those methods whose actual types are abstract SafeSet <Method> returnMethods = new SafeSet <Method>(); foreach (Method m in writeMethods) { TypeEx declType; if (m.TryGetDeclaringType(out declType) && !declType.IsAbstract && !declType.IsInterface) { returnMethods.Add(m); } } foreach (Method m in newWriteMethods) { TypeEx declType; if (m.TryGetDeclaringType(out declType) && !declType.IsAbstract && !declType.IsInterface) { returnMethods.Add(m); } } writeMethods.Clear(); writeMethods.AddRange(returnMethods); return(true); } //Identify those method that directly modify this field if (!TryGetWriteMethods(field, declaringType, out writeMethods)) { return(false); } //C# supports properties. In that case, the property setter can also //be a viable method. add property setter and its callers also Property property; if (MethodOrFieldAnalyzer.TryGetPropertyModifyingField(this, declaringType, field, out property)) { if (property.IsVisible(VisibilityContext.Exported)) { writeMethods.Add(property.Setter); } var newWriteMethods = new SafeSet <Method>(); GetCallingMethods(field, declaringType, writeMethods, newWriteMethods); writeMethods.AddRange(newWriteMethods); } writeMethods = FilterWriteMethodsOfUpdateType(field, desiredfmt, writeMethods); return(true); }
/// <summary> /// Gets a method store from a method signature /// </summary> /// <param name="msignature"></param> /// <param name="ms"></param> /// <returns></returns> public bool TryGetMethodStoreFromSignature(string msignature, out MethodStore ms) { foreach (var key in this.MethodDictionary.Keys) { string keysig = MethodOrFieldAnalyzer.GetMethodSignature(key); if (keysig == msignature) { ms = this.MethodDictionary[key]; return(true); } } ms = null; return(false); }
/// <summary> /// Accepts a method and returns the persistent string form "assemblyname#typename#methodsignature" of the method. /// </summary> /// <param name="method"></param> /// <returns></returns> public static string GetPersistentStringFormOfMethod(Method m) { var assemblyname = m.Definition.Module.Assembly.Location; string typename; TypeDefinition typedef = null; if (!m.Definition.TryGetDeclaringType(out typedef)) { SafeDebug.AssumeNotNull(typedef, "Type definition is empty"); typename = PexMeConstants.PexMeDummyTypeName; } else { typename = typedef.FullName; } var signature = MethodOrFieldAnalyzer.GetMethodSignature(m); return(assemblyname + PexMeConstants.PexMePersistenceFormSeparator + typename + PexMeConstants.PexMePersistenceFormSeparator + signature); }
/// <summary> /// Check whether a previously uncovered location is covered now in this run /// </summary> public bool IsPrevUncoveredLocationCovered(PersistentUncoveredLocationStore pucls) { //retrieve the method MethodDefinition associatedMethod; if (!MethodOrFieldAnalyzer.TryGetMethodDefinition(this, pucls.AssemblyShortName, pucls.declaringTypeStr, pucls.MethodSignature, out associatedMethod)) { this.Log.LogWarning(WikiTopics.MissingWikiTopic, "serialization", "Failed to retrieve the method with signature " + pucls.MethodSignature); return(false); } //Check whether the offset is covered in this method if (this.IsBranchOffsetCoveredInMethod(associatedMethod, pucls.Offset)) { return(true); } return(false); }
/// <summary> /// Checks whether a given method is an observer or not /// </summary> /// <param name="m"></param> /// <returns></returns> public bool IsAnObserver(Method method) { TypeEx declaringType; if (!method.TryGetDeclaringType(out declaringType)) { return(false); } MethodEffects me; if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, declaringType, method, null, out me)) { return(false); } if (me.WrittenInstanceFields.Count == 0) { return(true); } return(false); }
/// <summary> /// Adds a field to an unsuccessful code location. /// </summary> /// <param name="location"></param> /// <param name="fields"></param> public void AddFieldsOfUncoveredCodeLocations(CodeLocation location, SafeList <Field> fields, FieldModificationType fmt, Term condition, string terms, int fitnessval, TypeEx explorableType, SafeList <TypeEx> allFieldTypes) { //No need to process this location. if (fields.Count == 0) { return; } Field targetField; TypeEx declaringType; //This declaring type is considered as explorable type in the rest of the analysis if (!PexMeFactoryGuesser.GetTargetExplorableField(this, fields, out targetField, out declaringType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to retrieve the target field for uncovered location " + location.ToString()); return; } //Compare the declaring type and actual explorable type. //If there is a inheritance relation, use the actual one if (explorableType.IsAssignableTo(declaringType)) { declaringType = explorableType; } var uclskey = UncoveredCodeLocationStore.GetKey(location.ToString(), declaringType.ToString(), condition.UniqueIndex); UncoveredCodeLocationStoreList uclslist; if (!this.unCoveredLocationDic.TryGetValue(uclskey, out uclslist)) { uclslist = new UncoveredCodeLocationStoreList(); uclslist.Location = location; uclslist.ExplorableType = declaringType.ToString(); uclslist.TermIndex = condition.UniqueIndex; this.unCoveredLocationDic[uclskey] = uclslist; } var ucls = new UncoveredCodeLocationStore(); ucls.Location = location; ucls.ExplorableType = declaringType; ucls.TargetField = targetField; ucls.AllFields.AddRange(fields); ucls.AllFieldTypes.AddRange(allFieldTypes); ucls.TermIndex = condition.UniqueIndex; //add the sequence of method calls ucls.MethodCallSequence = new MethodSignatureSequence(); foreach (var m in this.LastExecutedFactoryMethodCallSequence) { ucls.MethodCallSequence.Sequence.Add(MethodOrFieldAnalyzer.GetMethodSignature(m)); } ucls.IsADefectDetectingSequence = this.DefectDetectingSequence; ucls.CUTMethodCallSequence = this.LastExecutedCUTMethodCallSequence; if (!uclslist.StoreList.Contains(ucls)) { ucls.TextualTerms.Add(terms); ucls.DesiredFieldModificationType = fmt; ucls.Fitnessvalue = fitnessval; uclslist.StoreList.Add(ucls); } }
/// <summary> /// Loads all inheritance hierarchies in the current library /// into TypeDictionary in the form of a tree suitable for traversal. /// </summary> public void LoadInheritanceHierarchies() { if (isInheritanceHierarchyLoaded) { return; } isInheritanceHierarchyLoaded = true; AssemblyEx currAssembly = this.Services.CurrentAssembly.Assembly.Assembly; foreach (var tdef in currAssembly.TypeDefinitions) { TypeStore currTypeStore; if (!this.TypeDictionary.TryGetValue(tdef, out currTypeStore)) { currTypeStore = new TypeStore(tdef); this.TypeDictionary.Add(tdef, currTypeStore); } var baseType = tdef.BaseTypeDefinition; //This restricts our implementation to a single assembly for time being. if (baseType != null && baseType.Module.Assembly == currAssembly) { TypeStore baseTypeStore; if (!this.TypeDictionary.TryGetValue(baseType, out baseTypeStore)) { baseTypeStore = new TypeStore(baseType); this.TypeDictionary.Add(baseType, baseTypeStore); } baseTypeStore.ExtendingTypes.Add(currTypeStore); } try { var typeEx = tdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(this, tdef)); if (typeEx != null) { foreach (var ifTypeEx in typeEx.DeclaredInterfaces) { var parentIfDef = ifTypeEx.Definition; if (parentIfDef.Module.Assembly != currAssembly) { continue; } TypeStore ifTypeStore; if (!this.TypeDictionary.TryGetValue(parentIfDef, out ifTypeStore)) { ifTypeStore = new TypeStore(parentIfDef); this.TypeDictionary.Add(parentIfDef, ifTypeStore); } ifTypeStore.ExtendingTypes.Add(currTypeStore); } } } catch (Exception ex) { this.Log.LogWarningFromException(ex, WikiTopics.MissingWikiTopic, "InheritanceLoader", "Failed to instantiate class " + tdef.FullName.ToString()); } } }
/// <summary> /// Gets the set of write methods associated with a field in the given type /// </summary> /// <param name="field"></param> /// <returns></returns> public bool TryGetWriteMethods(Field field, TypeEx declaringType, out SafeSet <Method> writeMethods) { SafeDebug.AssumeNotNull(field, "field"); SafeDebug.AssumeNotNull(declaringType, "declaringType"); //Declaring type should include defintinion if (declaringType == null || declaringType.Definition == null) { this.Log.LogWarning(WikiTopics.MissingWikiTopic, "WriteMethods", "Missing definition for the declaring type " + declaringType.FullName); writeMethods = null; return(false); } FieldStore fs; if (this.FieldDictionary.TryGetValue(field, out fs)) { if (fs.WriteMethods.TryGetValue(declaringType, out writeMethods)) { return(true); } else { writeMethods = new SafeSet <Method>(); fs.WriteMethods[declaringType] = writeMethods; } } else { fs = new FieldStore(); fs.FieldName = field; writeMethods = new SafeSet <Method>(); fs.WriteMethods[declaringType] = writeMethods; this.FieldDictionary[field] = fs; } foreach (MethodDefinition instanceMethod in declaringType.Definition.DeclaredInstanceMethods) { //Ignore abstract methods if (instanceMethod.IsAbstract) { continue; } //If the DISABLE_CALLING_METHODS_WITHIN_CLASS is set to true, then private methods need not be considered //since they will be filtered out. if (PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS && instanceMethod.DeclaredVisibility == Visibility.Private) { continue; } Method method = instanceMethod.Instantiate(declaringType.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(this, instanceMethod)); MethodEffects me; if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, declaringType, method, null, out me)) { this.Log.LogWarning(WikiTopics.MissingWikiTopic, "methodeffects", "Failed to get the method effects for method " + method); continue; } if (me.WrittenInstanceFields.Contains(field.ShortName)) { writeMethods.Add(method); } FieldModificationType fmt; if (me.ModificationTypeDictionary.TryGetValue(field.ShortName, out fmt)) { fs.ModificationTypeDictionary[method] = fmt; } } //Check whether there are any private methods in calling methods. //If yes, replace them with their callers. if (!PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS) { var newWriteMethods = new SafeSet <Method>(); GetCallingMethods(field, declaringType, writeMethods, newWriteMethods); writeMethods.Clear(); writeMethods.AddRange(newWriteMethods); } TypeEx baseType = declaringType.BaseType; if (baseType != null && baseType.FullName != "System.Object") { SafeSet <Method> innerWriteMethods; this.TryGetWriteMethods(field, baseType, out innerWriteMethods); if (innerWriteMethods != null) { writeMethods.AddRange(innerWriteMethods); } } return(true); }
/// <summary> /// Gets calling methods of a given called method on the given field in a given target type /// </summary> /// <returns></returns> public bool TryGetCallingMethodsInType(Method calledMethod, Field field, TypeEx targetType, out SafeSet <Method> callingMethods) { SafeDebug.AssumeNotNull(calledMethod, "method"); SafeDebug.AssumeNotNull(targetType, "type"); //Get the associated property of the field Property property; if (!MethodOrFieldAnalyzer.TryGetPropertyReadingField(this, targetType, field, out property)) { //TODO: error; } MethodStore mstore = null; if (this.MethodDictionary.TryGetValue(calledMethod, out mstore)) { if (mstore.CallingMethods.TryGetValue(targetType, out callingMethods)) { return(true); } } //No method store found. create a fresh one if (mstore == null) { mstore = new MethodStore(); mstore.methodName = calledMethod; this.MethodDictionary[calledMethod] = mstore; } callingMethods = new SafeSet <Method>(); mstore.CallingMethods[targetType] = callingMethods; TypeEx calledMethodType; if (!calledMethod.TryGetDeclaringType(out calledMethodType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods", "Failed to get the declaring type for the method " + calledMethod.FullName); return(false); } //Needs to addess the array type issue over here. var targetdef = targetType.Definition; if (targetdef == null) { if (targetType.TypeKind != TypeKind.SzArrayElements) { this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods", "The definition for the type " + targetType.FullName + " is null"); return(false); } else { targetdef = targetType.ElementType.Definition; } } //Analyze each method in the given type to identify the calling methods //of the given method foreach (var typeMethod in targetdef.DeclaredInstanceMethods) { Method minstance = typeMethod.Instantiate(targetType.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(this, typeMethod)); MethodEffects meffects; if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, targetType, minstance, null, out meffects)) { continue; } //Check for a direct comparison if (meffects.DirectCalledMethods.Contains(calledMethod)) { callingMethods.Add(minstance); } else { //Use vtable lookup for addressing the abstract issues foreach (var dcallMethod in meffects.DirectCalledMethods) { if (dcallMethod.IsConstructor) { continue; } TypeEx dcallMethodType; if (dcallMethod.TryGetDeclaringType(out dcallMethodType)) { if (dcallMethodType == calledMethodType || !dcallMethodType.IsAbstract || !dcallMethodType.IsInterface) { continue; } if (!dcallMethodType.IsAssignableTo(calledMethodType) && !calledMethodType.IsAssignableTo(dcallMethodType)) { continue; } } try { var lookupMethod = calledMethodType.VTableLookup(dcallMethod); if (lookupMethod != null && calledMethod == lookupMethod) { callingMethods.Add(minstance); break; } } catch (Exception ex) { this.Log.LogWarningFromException(ex, WikiTopics.MissingWikiTopic, "vtablelookup", "Failed to perform vtablelookup for " + dcallMethod.FullName + " in type " + calledMethodType.FullName); } } } } //Check whether there are any private methods in calling methods. //If yes, replace them with their callers. if (!PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS) { var newCallingMethods = new SafeSet <Method>(); foreach (var callingM in callingMethods) { if (callingM.Definition.DeclaredVisibility != Visibility.Private || callingM.IsConstructor) { newCallingMethods.Add(callingM); continue; } //Get other calling methods within this type SafeSet <Method> localCM; if (this.TryGetCallingMethodsInType(callingM, field, targetType, out localCM)) { newCallingMethods.AddRange(localCM); } } callingMethods.Clear(); callingMethods.AddRange(newCallingMethods); } //Needs to further analyze parent types TypeEx baseType = targetType.BaseType; if (baseType != null && baseType.FullName != "System.Object") //TODO: Avoid string comparisons. needs to figure out how to do that { SafeSet <Method> baseCallingMethods; TryGetCallingMethodsInType(calledMethod, field, baseType, out baseCallingMethods); callingMethods.AddRange(baseCallingMethods); } return(true); }