/* The CheckLineLenght Method which is called from * MainWindowControl.xaml.cs when the assigned button is pressed */ public void CheckLineLength(List <Document> documents, int numChars) { foreach (var document in documents) { if (document != null) { /* convert the document to a text * so every line can be accesed */ Task <SourceText> t = document.GetTextAsync(); SourceText doctext = t.Result; if (doctext != null) { foreach (var line in doctext.Lines) { if (line.ToString().Length > numChars) { ErrorReporter.AddWarning( "Line " + (line.LineNumber + 1) + " in Document " + document.Name + " is too long!", document.FilePath, line.LineNumber ); } } } } } }
/* this method checks if the namingconventions for namespaces * set by the user are met for all documents in the project */ public void Namespacenaming( List <NamespaceDeclarationSyntax> list, String projekt, List <string> folders, Document document) { String desiredNamespace = projekt; if (list.Count > 1) { } list.ForEach(delegate(NamespaceDeclarationSyntax nds) { folders.ForEach(delegate(string folder) { desiredNamespace += "." + folder; }); if (!nds.Name.Equals(desiredNamespace)) { int line = nds.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Wrong namespace : " + nds.Name + "! Should be : " + desiredNamespace + "!", document.FilePath, line); } }); }
/* this method checks if the namingconventions for classes * set by the user are met for all documents in the project */ public void Classnaming( List <ClassDeclarationSyntax> list, Document document) { list.ForEach(delegate(ClassDeclarationSyntax cds) { string currentClassName = cds.Identifier.ToString(); /* determine whether the class name only contains * letters of the abc and if the first letter is in uppercase */ if (char.IsUpper(currentClassName[0]) && Regex.Matches(currentClassName, @"[a-zA-Z ]"). Count == currentClassName.Length) { } else { int line = cds.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Flawed class name : " + cds.Identifier, document.FilePath, line); } }); }
/* this method checks whether the view knows the model or * the other way around. * This will be the case if an object of the other * is instantiated anywhere within it. */ public void ModelknowsViews( List <ClassDeclarationSyntax> classModellist, List <ClassDeclarationSyntax> classViewlist, List <Tuple <ObjectCreationExpressionSyntax, Document> > idModellist, List <Tuple <ObjectCreationExpressionSyntax, Document> > idViewlist) { classModellist.ForEach(delegate(ClassDeclarationSyntax cdsm) { string modelClassname = cdsm.Identifier.ToString(); idViewlist.ForEach( delegate( Tuple <ObjectCreationExpressionSyntax, Document> tuple) { string createdObject = tuple.Item1.ToString(); if (createdObject.Contains(modelClassname)) { int line = tuple.Item1.GetLocation(). GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "View accessing model!", tuple.Item2.FilePath, line); } }); }); classViewlist.ForEach(delegate(ClassDeclarationSyntax cdsv) { string viewClassname = cdsv.Identifier.ToString(); idModellist.ForEach( delegate( Tuple <ObjectCreationExpressionSyntax, Document> tuple) { string createdObject = tuple.Item1.ToString(); if (createdObject.Contains(viewClassname)) { int line = tuple.Item1.GetLocation(). GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Model accessing view!", tuple.Item2.FilePath, line); } }); }); }
/*this method checks if the code behind file is left empty. * Every code behind file has a .xaml as its parent * which is treatet like its folder. */ public void CheckCodeBehind(Project project) { foreach (var document in project.Documents) { if (document != null) { Task <SyntaxTree> t = document.GetSyntaxTreeAsync(); SyntaxTree tree = t.Result; /* get every method/variable and * propertydeclaration of the current document */ List <MethodDeclarationSyntax> methodDeclarations = tree.GetRoot().DescendantNodesAndSelf(). OfType <MethodDeclarationSyntax>().ToList(); List <VariableDeclarationSyntax> variableDeclarations = tree.GetRoot().DescendantNodesAndSelf(). OfType <VariableDeclarationSyntax>().ToList(); List <PropertyDeclarationSyntax> propertyDeclarations = tree.GetRoot().DescendantNodesAndSelf(). OfType <PropertyDeclarationSyntax>().ToList(); List <string> folders = document.Folders.ToList(); folders.ForEach(delegate(string folder) { //check if any declarations are in the code behind file if (folder.Contains(".xaml") && (methodDeclarations.Any() || variableDeclarations.Any() || propertyDeclarations.Any())) { ErrorReporter.AddWarning( "Codebehind is not empty!", document.FilePath); } }); } } }
/* The CheckImports Method which is called from * MainWindowControl.xaml.cs when the assigned button is pressed */ public void CheckImports(List <Document> documents) { foreach (var document in documents) { if (document != null) { Compilation compilation; Task <Compilation> taskc = document.Project. GetCompilationAsync(); compilation = taskc.Result; SyntaxTree tree; Task <SyntaxTree> taskst = document.GetSyntaxTreeAsync(); tree = taskst.Result; var root = tree.GetRoot(); /* part of this snippet is taken from a solution provided * by Jon Skeet in his Stackoverflow post * https://stackoverflow.com/questions/44058243/how-can-i-detect-unused-imports-in-a-script-rather-than-a-document-with-roslyn */ var unusedImportNodes = compilation.GetDiagnostics() .Where(d => d.Id == "CS8019") .Where(d => d.Location?.SourceTree == tree) .Select(d => root.FindNode(d.Location.SourceSpan)) .ToList(); unusedImportNodes.ForEach(delegate(SyntaxNode nd) { int line = nd.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning("Unused import : " + nd.ToString(), document.FilePath, line); }); } } }
public void CheckSingleton( Project project, ObservableCollection <Document> documents, bool checkThreadSafety) { foreach (Document d in documents) { // Get SyntaxTree for Document Task <SyntaxTree> t = d.GetSyntaxTreeAsync(); SyntaxTree tree = t.Result; // Get List of class declarations from SyntaxTree List <ClassDeclarationSyntax> classDeclarations = tree.GetRoot().DescendantNodes(). OfType <ClassDeclarationSyntax>().ToList(); foreach (ClassDeclarationSyntax classDec in classDeclarations) { // Get List of constructor declarations in class List <ConstructorDeclarationSyntax> constructorDeclarations = classDec.DescendantNodes(). OfType <ConstructorDeclarationSyntax>().ToList(); string className = classDec.Identifier.Text; bool isSingleton = true; /* Check all class constructors for * whether or not they are private */ if (!constructorDeclarations.Any()) { isSingleton = false; } else { foreach ( ConstructorDeclarationSyntax constDec in constructorDeclarations) { List <SyntaxToken> tokens = constDec.ChildTokens().ToList(); bool isPrivate = false; foreach (SyntaxToken token in tokens) { if (token.IsKind(SyntaxKind.PrivateKeyword)) { isPrivate = true; } } if (!isPrivate) { isSingleton = false; } } } if (!isSingleton) { int line = classDec.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Class " + className + " contained in document " + d.Name + " is not singleton but it should be!", d.FilePath, line); } /* Consider the class Singleton * as long as all constructors are private */ if (isSingleton && checkThreadSafety) { /* With information from * http://csharpindepth.com/Articles/General/Singleton.aspx */ /* Check whether Singleton is thread safe * by way of double check locking */ if (IsDoubleCheckLocked(classDec)) { } /* If it is not, check if it is thread safe * through use of .NET's Lazy<T>-class */ else if (IsLazy(classDec)) { } /* If singleton is neither double check locked * nor Lazy-instantiated, add warning * */ else { int line = classDec.GetLocation(). GetMappedLineSpan().StartLinePosition.Line; ErrorReporter.AddWarning( "Class " + className + " contained in document " + d.Name + " is neither double check locked nor lazy! \n" + "Consider adding either one for thread safety." , d.FilePath, line); } } else { } } } }
/* this method checks if the namingconventions for methods * set by the user are met for all documents in the project */ public void Methodnaming( List <MethodDeclarationSyntax> list, List <string> permittedMethods, Document document, MainWindowControl.NameCase nameCaseMethod) { list.ForEach(delegate(MethodDeclarationSyntax mds) { string currentMethodName = mds.Identifier.ToString(); string regexmatchstring = currentMethodName; /* permitted special signs get treated like * they are not part of the methodname */ if (permittedMethods.Equals("")) { permittedMethods.ForEach(delegate(string permitted) { regexmatchstring = regexmatchstring.Replace( permitted, ""); }); } /* determin whether the method name * only contains letters of the abc */ if (Regex.Matches(regexmatchstring, @"[a-zA-Z ]"). Count == regexmatchstring.Length) { //check if camelCase constraint is violated if (char.IsUpper(regexmatchstring[0]) && nameCaseMethod. Equals(MainWindowControl.NameCase.camelCase)) { int line = mds.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Method name should be camelCase : " + mds.Identifier, document.FilePath, line); } //check if PascalCase constraint is violated if (char.IsLower(regexmatchstring[0]) && nameCaseMethod. Equals(MainWindowControl.NameCase.PascalCase)) { int line = mds.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Method name should be PascalCase : " + mds.Identifier, document.FilePath, line); } } else { int line = mds.GetLocation().GetMappedLineSpan(). StartLinePosition.Line; ErrorReporter.AddWarning( "Illegal character in method name : " + mds.Identifier, document.FilePath, line); } }); }