/// <summary> /// Initializes a new instance of the SyntaxException class. /// </summary> /// <param name="sourceCode"> /// The source code document containing the exception. /// </param> /// <param name="lineNumber"> /// The line number of the exception. /// </param> public SyntaxException(SourceCode sourceCode, int lineNumber) : base(string.Format(CultureInfo.CurrentCulture, Strings.SyntaxErrorInFile, sourceCode.Path, lineNumber)) { Param.RequireNotNull(sourceCode, "sourceCode"); Param.RequireGreaterThanZero(lineNumber, "lineNumber"); this.sourceCode = sourceCode; this.lineNumber = lineNumber; }
/// <summary> /// Initializes a new instance of the SyntaxException class. /// </summary> /// <param name="sourceCode"> /// The source code document containing the exception. /// </param> /// <param name="lineNumber"> /// The line number of the exception. /// </param> /// <param name="innerException"> /// The exception within this exception. /// </param> public SyntaxException(SourceCode sourceCode, int lineNumber, Exception innerException) : base(string.Format(CultureInfo.CurrentCulture, Strings.SyntaxErrorInFile, sourceCode.Path, lineNumber), innerException) { Param.RequireNotNull(sourceCode, "sourceCode"); Param.RequireGreaterThanZero(lineNumber, "lineNumber"); Param.Ignore(innerException); this.sourceCode = sourceCode; this.lineNumber = lineNumber; }
/// <summary> /// Initializes a new instance of the SyntaxException class. /// </summary> /// <param name="sourceCode"> /// The source code document containing the exception. /// </param> /// <param name="lineNumber"> /// The line number of the exception. /// </param> /// <param name="message"> /// The exception message. /// </param> public SyntaxException(SourceCode sourceCode, int lineNumber, string message) : base(string.Format(CultureInfo.CurrentCulture, Strings.SyntaxErrorInFileWithMessage, sourceCode.Path, lineNumber, message)) { Param.RequireNotNull(sourceCode, "sourceCode"); Param.RequireGreaterThanZero(lineNumber, "lineNumber"); Param.RequireValidString(message, "message"); this.sourceCode = sourceCode; this.lineNumber = lineNumber; }
/// <summary> /// Disposes the contents of the class. /// </summary> /// <param name="disposing"> /// Indicates whether to dispose unmanaged resources. /// </param> protected virtual void Dispose(bool disposing) { Param.Ignore(disposing); if (disposing) { this.sourceCode = null; this.analyzerData = null; } }
/// <summary> /// Opens the results cache for the given source code document. /// </summary> /// <param name="sourceCode"> /// The source code document. /// </param> /// <param name="parser"> /// The parser that created the document. /// </param> /// <param name="item"> /// Returns the node from the results cache for this code document. /// </param> /// <returns> /// Returns the results cache. /// </returns> private XmlDocument OpenResultsCache(SourceCode sourceCode, SourceParser parser, out XmlNode item) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parser, "parser"); item = null; XmlDocument doc = null; try { lock (this) { // Determine whether this results cache is already in our list. if (this.documentHash.TryGetValue(sourceCode.Project.Location, out doc)) { // Now pull out the section for this source code document. item = doc.DocumentElement.SelectSingleNode( string.Format(CultureInfo.InvariantCulture, "sourcecode[@name=\"{0}\"][@parser=\"{1}\"]", sourceCode.Name, parser.Id)); } else { doc = this.core.Environment.LoadResultsCache(sourceCode.Project.Location); if (doc != null) { // Get the version and make sure it matches. XmlElement node = doc["stylecopresultscache"]["version"]; if (node.InnerText == ResultsCache.Version) { // Now pull out the section for this source code document. item = doc.DocumentElement.SelectSingleNode( string.Format(CultureInfo.InvariantCulture, "sourcecode[@name=\"{0}\"][@parser=\"{1}\"]", sourceCode.Name, parser.Id)); } else { // Since the version does not match, ignore this document. doc = null; } } } } } catch (XmlException) { doc = null; } catch (NullReferenceException) { doc = null; } return(doc); }
/// <summary> /// Adds the given source code document to the project. /// </summary> /// <param name="sourceCode"> /// The source code to add. /// </param> internal virtual void AddSourceCode(SourceCode sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); if (string.IsNullOrEmpty(sourceCode.Type)) { throw new ArgumentException(Strings.SourceCodeTypePropertyNotSet); } this.sourceCodes.Add(sourceCode); }
/// <summary> /// Initializes a new instance of the Violation class. /// </summary> /// <param name="rule">The rule that triggered the violation.</param> /// <param name="sourceCode">The source code that this violation appears in.</param> /// <param name="line">The line in the source code where the violation occurs.</param> /// <param name="message">The context message for the violation.</param> internal Violation(Rule rule, SourceCode sourceCode, int line, string message) { Param.AssertNotNull(rule, "rule"); Param.Ignore(sourceCode); Param.AssertGreaterThanOrEqualToZero(line, "line"); Param.AssertNotNull(message, "message"); this.rule = rule; this.sourceCode = sourceCode; this.line = line; this.message = message; }
/// <summary> /// Returns the leafname of the source code path. /// </summary> /// <param name="sourceCode"> /// The SourceCode object to use. /// </param> /// <returns> /// The leafname. /// </returns> private static string GetRelativeFileName(SourceCode sourceCode) { string sourceCodePath = sourceCode.Path; string sourceCodeProjectLocation = sourceCode.Project.Location; string outputText = sourceCode.Name; if (sourceCodePath != null && sourceCodeProjectLocation != null && sourceCodePath.StartsWith(sourceCodeProjectLocation, true, CultureInfo.InvariantCulture)) { outputText = sourceCodePath.SubstringAfter(sourceCodeProjectLocation, StringComparison.InvariantCultureIgnoreCase); } return(outputText); }
/// <summary> /// Loads results for the given source code document from the cache. /// </summary> /// <param name="sourceCode">The source code to load.</param> /// <param name="parser">The parser that created this document.</param> /// <param name="writeTime">The last write time of the document.</param> /// <param name="settingsTimeStamp">The time when the settings were last updated.</param> /// <returns>Returns true if the results were loaded from the cache.</returns> public bool LoadResults(SourceCode sourceCode, SourceParser parser, DateTime writeTime, DateTime settingsTimeStamp) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parser, "parser"); Param.Ignore(writeTime); Param.Ignore(settingsTimeStamp); bool success = false; lock (this) { XmlNode item = null; XmlDocument doc = this.OpenResultsCache(sourceCode, parser, out item); if (doc != null && item != null) { try { // Check the settings file timestamp. XmlElement settingsNode = item["settings"]; if (settingsNode != null && IsNodeUpToDate(settingsNode, settingsTimeStamp)) { // Get the timestamp and make sure the file has not been changed // since this cache was written. if (IsNodeUpToDate(item, writeTime)) { XmlNode violations = item.SelectSingleNode("violations"); if (violations != null) { if (parser.ImportViolations(sourceCode, violations)) { success = true; } } } } } catch (XmlException) { } if (!this.documentHash.ContainsKey(sourceCode.Project.Location)) { this.documentHash.Add(sourceCode.Project.Location, doc); } } } return success; }
/// <summary> /// Adds one violation to the given source code document. /// </summary> /// <param name="sourceCode">The source code document that the violation appears in.</param> /// <param name="line">The line in the code where the violation occurs.</param> /// <param name="ruleName">The name of the rule that triggered the violation.</param> /// <param name="values">String parameters to insert into the violation string.</param> public void AddViolation(SourceCode sourceCode, int line, string ruleName, params object[] values) { Param.Ignore(sourceCode, line, ruleName, values); Rule rule = this.GetRule(ruleName); if (rule == null) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.RuleDoesNotExist, ruleName), "ruleName"); } // Look up this violation type. this.Core.AddViolation(sourceCode, rule, line, values); }
/// <summary> /// Loads results for the given source code document from the cache. /// </summary> /// <param name="sourceCode">The source code to load.</param> /// <param name="parser">The parser that created this document.</param> /// <param name="writeTime">The last write time of the document.</param> /// <param name="settingsTimeStamp">The time when the settings were last updated.</param> /// <returns>Returns true if the results were loaded from the cache.</returns> public bool LoadResults(SourceCode sourceCode, SourceParser parser, DateTime writeTime, DateTime settingsTimeStamp) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parser, "parser"); Param.Ignore(writeTime); Param.Ignore(settingsTimeStamp); bool success = false; lock (this) { XmlNode item = null; XmlDocument doc = this.OpenResultsCache(sourceCode, parser, out item); if (doc != null && item != null) { try { // Check the settings file timestamp. XmlElement settingsNode = item["settings"]; if (settingsNode != null && IsNodeUpToDate(settingsNode, settingsTimeStamp)) { // Get the timestamp and make sure the file has not been changed // since this cache was written. if (IsNodeUpToDate(item, writeTime)) { XmlNode violations = item.SelectSingleNode("violations"); if (violations != null) { if (parser.ImportViolations(sourceCode, violations)) { success = true; } } } } } catch (XmlException) { } if (!this.documentHash.ContainsKey(sourceCode.Project.Location)) { this.documentHash.Add(sourceCode.Project.Location, doc); } } } return(success); }
/// <summary> /// Gets the analysis status for the given source code document. /// </summary> /// <param name="sourceCode">The source code to retrieve status for.</param> /// <returns>Returns the analysis status for the source code.</returns> public DocumentAnalysisStatus GetDocumentStatus(SourceCode sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); DocumentAnalysisStatus status; if (!this.sourceCodeInstanceStatus.TryGetValue(sourceCode, out status)) { // Create a new status object and add add it to the dictionary. status = new DocumentAnalysisStatus(); this.sourceCodeInstanceStatus.Add(sourceCode, status); } return(status); }
/// <summary> /// Gets the next source code document to analyze. /// </summary> /// <returns>Returns the source code document to analyze or null if none.</returns> public SourceCode GetNextSourceCodeDocument() { // Keep looping until we find a file that is not marked as excluded. while (true) { SourceCode sourceCode = this.ExtractNextSourceCodeDocument(); if (sourceCode == null) { return(null); } sourceCode.Settings = sourceCode.Project.Settings.GetCustomSettingsForFile(sourceCode.Name); return(sourceCode); } }
/// <summary> /// Initializes a new instance of the Violation class. /// </summary> /// <param name="rule">The rule that triggered the violation.</param> /// <param name="element">The element that this violation appears in.</param> /// <param name="line">The line in the source code where the violation occurs.</param> /// <param name="message">The context message for the violation.</param> internal Violation(Rule rule, ICodeElement element, int line, string message) { Param.AssertNotNull(rule, "rule"); Param.Ignore(element); Param.AssertGreaterThanOrEqualToZero(line, "line"); Param.AssertNotNull(message, "message"); this.rule = rule; this.element = element; this.line = line; this.message = message; if (this.element != null && this.element.Document != null) { this.sourceCode = this.element.Document.SourceCode; } }
/// <summary> /// Pulls out the next source code document. /// </summary> /// <returns>Returns the source code document to analyze or null if none.</returns> private SourceCode ExtractNextSourceCodeDocument() { SourceCode sourceCode = null; while (this.projectIndex < this.projects.Count) { CodeProject project = this.projects[this.projectIndex]; ++this.sourceCodeInstanceIndex; if (this.sourceCodeInstanceIndex >= project.SourceCodeInstances.Count) { ++this.projectIndex; this.sourceCodeInstanceIndex = -1; } else { sourceCode = project.SourceCodeInstances[this.sourceCodeInstanceIndex]; break; } } return(sourceCode); }
/// <summary> /// Initializes a new instance of the Violation class. /// </summary> /// <param name="rule"> /// The rule that triggered the violation. /// </param> /// <param name="element"> /// The element that this violation appears in. /// </param> /// <param name="line"> /// The line in the source code where the violation occurs. /// </param> /// <param name="message"> /// The context message for the violation. /// </param> internal Violation(Rule rule, ICodeElement element, int line, string message) { Param.AssertNotNull(rule, "rule"); Param.Ignore(element); Param.AssertGreaterThanOrEqualToZero(line, "line"); Param.AssertNotNull(message, "message"); this.rule = rule; this.element = element; this.line = line; // As the line only is passed in we ensure the location is null. // A null location indicates we only know the line it was on. this.location = null; this.message = message; if (this.element != null && this.element.Document != null) { this.sourceCode = this.element.Document.SourceCode; } this.UpdateKey(); }
/// <summary> /// Saves the fixed document back to the source location. /// </summary> /// <param name="sourceCode">The source code representing the source of the document.</param> /// <param name="document">The document to save to the source code location.</param> private void SaveDocumentToSource(SourceCode sourceCode, ICodeDocument document) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(document, "document"); Exception exception; if (!sourceCode.Write(document, out exception)) { if (exception != null) { this.data.Core.CoreViolations.AddViolation(null, 1, Rules.SaveExceptionOccurred, exception.GetType(), sourceCode.Path, exception.Message); } else { this.data.Core.CoreViolations.AddViolation(null, 1, Rules.UnknownSaveExceptionOccurred, sourceCode.Path); } } else { document.Dirty = false; } }
/// <summary> /// Adds a source code document to the given project. /// </summary> /// <param name="project"> /// The project which should contain the source code instance. /// </param> /// <param name="path"> /// The path to the source code document to add. /// </param> /// <param name="context"> /// Optional context information. /// </param> /// <returns> /// Returns true if any source code documents were added to the project. /// </returns> public override bool AddSourceCode(CodeProject project, string path, object context) { Param.RequireNotNull(project, "project"); Param.RequireValidString(path, "path"); Param.Ignore(context); bool added = false; // Get the parsers for this file based on its extension. string extension = Path.GetExtension(path); if (extension != null && extension.Length > 0) { // Remove the leading dot and convert the extension to lower-case. extension = extension.Substring(1).ToUpperInvariant(); ICollection <SourceParser> parserList = this.GetParsersForFileType(extension); if (parserList != null) { // Create SourceCode objects representing this file, for each parser. foreach (SourceParser parser in parserList) { // Create and return a SourceCode for this file. SourceCode source = this.sourceCodeFactory(path, project, parser, context); if (source == null) { throw new InvalidOperationException(Strings.SourceCodeFactoryReturnsNull); } project.AddSourceCode(source); added = true; } } } return(added); }
/// <summary> /// Loads results for the given source code document from the cache. /// </summary> /// <param name="sourceCode"> /// The source code to load. /// </param> /// <param name="parser"> /// The parser that created this document. /// </param> /// <param name="writeTime"> /// The last write time of the document. /// </param> /// <param name="settingsTimestamp"> /// The time when the settings were last updated. /// </param> /// <returns> /// Returns true if the results were loaded from the cache. /// </returns> public bool LoadResults(SourceCode sourceCode, SourceParser parser, DateTime writeTime, DateTime settingsTimestamp) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parser, "parser"); Param.Ignore(writeTime); Param.Ignore(settingsTimestamp); lock (this) { XmlNode item = null; XmlDocument doc = this.OpenResultsCache(sourceCode, parser, out item); if (doc != null && item != null) { if (!this.documentHash.ContainsKey(sourceCode.Project.Location)) { this.documentHash.Add(sourceCode.Project.Location, doc); } try { // Check the timestamps of all the files. if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/styleCop"), this.core.TimeStamp)) { return(false); } if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/settingsFile"), settingsTimestamp)) { return(false); } if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/sourceFile"), writeTime)) { return(false); } if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/parser"), parser.TimeStamp)) { return(false); } foreach (SourceAnalyzer analyzer in parser.Analyzers) { if (!IsNodeUpToDate(item.SelectSingleNode(string.Concat("timestamps/", analyzer.Id)), analyzer.TimeStamp)) { return(false); } if ( !IsNodeUpToDate( item.SelectSingleNode(string.Concat("timestamps/", analyzer.Id + ".FilesHashCode")), analyzer.GetDependantFilesHashCode(sourceCode.Project.Culture))) { return(false); } } XmlNode violations = item.SelectSingleNode("violations"); if (violations != null) { if (parser.ImportViolations(sourceCode, violations)) { return(true); } } } catch (XmlException) { } } } return(false); }
/// <summary> /// Loads results for the given source code document from the cache. /// </summary> /// <param name="sourceCode"> /// The source code to load. /// </param> /// <param name="parser"> /// The parser that created this document. /// </param> /// <param name="writeTime"> /// The last write time of the document. /// </param> /// <param name="settingsTimestamp"> /// The time when the settings were last updated. /// </param> /// <returns> /// Returns true if the results were loaded from the cache. /// </returns> public bool LoadResults(SourceCode sourceCode, SourceParser parser, DateTime writeTime, DateTime settingsTimestamp) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parser, "parser"); Param.Ignore(writeTime); Param.Ignore(settingsTimestamp); lock (this) { XmlNode item = null; XmlDocument doc = this.OpenResultsCache(sourceCode, parser, out item); if (doc != null && item != null) { if (!this.documentHash.ContainsKey(sourceCode.Project.Location)) { this.documentHash.Add(sourceCode.Project.Location, doc); } try { // Check the timestamps of all the files. if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/styleCop"), this.core.TimeStamp)) { return false; } if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/settingsFile"), settingsTimestamp)) { return false; } if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/sourceFile"), writeTime)) { return false; } if (!IsNodeUpToDate(item.SelectSingleNode("timestamps/parser"), parser.TimeStamp)) { return false; } foreach (SourceAnalyzer analyzer in parser.Analyzers) { if (!IsNodeUpToDate(item.SelectSingleNode(string.Concat("timestamps/", analyzer.Id)), analyzer.TimeStamp)) { return false; } if ( !IsNodeUpToDate( item.SelectSingleNode(string.Concat("timestamps/", analyzer.Id + ".FilesHashCode")), analyzer.GetDependantFilesHashCode(sourceCode.Project.Culture))) { return false; } } XmlNode violations = item.SelectSingleNode("violations"); if (violations != null) { if (parser.ImportViolations(sourceCode, violations)) { return true; } } } catch (XmlException) { } } } return false; }
/// <summary> /// Adds a generic violation. /// </summary> /// <param name="sourceCode">The file to add the violation to.</param> /// <param name="violation">The violation to add to the element.</param> internal void AddViolation(SourceCode sourceCode, Violation violation) { Param.Ignore(sourceCode, "sourceCode"); Param.AssertNotNull(violation, "violation"); bool signal = true; // Add the violation to the file. if (sourceCode != null) { if (!sourceCode.AddViolation(violation)) { signal = false; } } // Signal that there is a new violation. if (signal) { this.OnViolationEncountered(new ViolationEventArgs(violation)); } }
/// <summary> /// Gets the analysis status for the given source code document. /// </summary> /// <param name="sourceCode">The source code to retrieve status for.</param> /// <returns>Returns the analysis status for the source code.</returns> public DocumentAnalysisStatus GetDocumentStatus(SourceCode sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); DocumentAnalysisStatus status; if (!this.sourceCodeInstanceStatus.TryGetValue(sourceCode, out status)) { // Create a new status object and add add it to the dictionary. status = new DocumentAnalysisStatus(); this.sourceCodeInstanceStatus.Add(sourceCode, status); } return status; }
/// <summary> /// Initializes a new instance of the CodeDocument class. /// </summary> /// <param name="sourceCode"> /// The source code document this instance represents. /// </param> protected CodeDocument(SourceCode sourceCode) { Param.RequireNotNull(sourceCode, "sourceCode"); this.sourceCode = sourceCode; }
/// <summary> /// Initializes a new instance of the SyntaxException class. /// </summary> /// <param name="sourceCode"> /// The source code document containing the exception. /// </param> /// <param name="lineNumber"> /// The line number of the exception. /// </param> /// <param name="message"> /// The exception message. /// </param> /// <param name="innerException"> /// The exception within this exception. /// </param> public SyntaxException(SourceCode sourceCode, int lineNumber, string message, Exception innerException) : base(string.Format(CultureInfo.CurrentCulture, Strings.SyntaxErrorInFileWithMessage, sourceCode.Path, lineNumber, message), innerException) { Param.RequireNotNull(sourceCode, "sourceCode"); Param.RequireGreaterThanZero(lineNumber, "lineNumber"); Param.RequireValidString(message, "message"); Param.Ignore(innerException); this.sourceCode = sourceCode; this.lineNumber = lineNumber; }
/// <summary> /// Adds one violation to the given source code document. /// </summary> /// <param name="sourceCode">The source code document that the violation appears in.</param> /// <param name="line">The line in the code where the violation occurs.</param> /// <param name="ruleName">The name of the rule that triggered the violation.</param> /// <param name="values">String parameters to insert into the violation string.</param> public void AddViolation(SourceCode sourceCode, int line, Enum ruleName, params object[] values) { Param.Ignore(sourceCode); Param.Ignore(line); Param.RequireNotNull(ruleName, "ruleName"); Param.Ignore(values); this.AddViolation(sourceCode, line, ruleName.ToString(), values); }
/// <summary> /// Imports the cached violations under the given node. /// </summary> /// <param name="sourceCode">The source code containing the violations.</param> /// <param name="parentNode">The parent xml node containing the list of violations.</param> /// <returns>Returns true if all the data was loaded successfully from the file.</returns> internal bool ImportViolations(SourceCode sourceCode, XmlNode parentNode) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parentNode, "parentNode"); bool success = true; try { XmlNodeList violations = parentNode.SelectNodes("violation"); if (violations != null && violations.Count > 0) { foreach (XmlNode violationNode in violations) { // Get the violation data from the xml node. XmlNode nameSpace = violationNode.SelectSingleNode("@namespace"); XmlNode ruleName = violationNode.SelectSingleNode("@rule"); XmlNode ruleCheckId = violationNode.SelectSingleNode("@ruleCheckId"); XmlNode context = violationNode.SelectSingleNode("context"); XmlNode lineNumber = violationNode.SelectSingleNode("line"); XmlNode warning = violationNode.SelectSingleNode("warning"); // Create a Rule object representing this data. Rule rule = new Rule( ruleName.InnerText, nameSpace.InnerText, ruleCheckId.InnerText, context.InnerText, Convert.ToBoolean(warning.InnerText, CultureInfo.InvariantCulture)); // Create a Violation object representing this data. Violation violation = new Violation( rule, sourceCode, Convert.ToInt32(lineNumber.InnerText, null), context.InnerText); this.AddViolation(violation); } } } catch (ArgumentException) { success = false; } catch (XmlException) { success = false; } catch (FormatException) { success = false; } catch (OverflowException) { success = false; } return success; }
/// <summary> /// Indicates whether to skip analysis on the given document. /// </summary> /// <param name="sourceCode"> /// The sourceCode to check. /// </param> /// <returns> /// Returns true to skip analysis on the document. /// </returns> public virtual bool SkipAnalysisForDocument(SourceCode sourceCode) { Param.Ignore(sourceCode); return false; }
/// <summary> /// Imports the cached violations under the given node. /// </summary> /// <param name="sourceCode"> /// The source code containing the violations. /// </param> /// <param name="parentNode"> /// The parent xml node containing the list of violations. /// </param> /// <returns> /// Returns true if all the data was loaded successfully from the file. /// </returns> internal bool ImportViolations(SourceCode sourceCode, XmlNode parentNode) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parentNode, "parentNode"); bool success = true; try { XmlNodeList violations = parentNode.SelectNodes("violation"); if (violations != null && violations.Count > 0) { foreach (XmlNode violationNode in violations) { // Get the violation data from the xml node. XmlNode nameSpace = violationNode.SelectSingleNode("@namespace"); XmlNode ruleName = violationNode.SelectSingleNode("@rule"); XmlNode ruleCheckId = violationNode.SelectSingleNode("@ruleCheckId"); XmlNode context = violationNode.SelectSingleNode("context"); XmlNode lineNumber = violationNode.SelectSingleNode("line"); XmlNode warning = violationNode.SelectSingleNode("warning"); XmlNode index = violationNode.SelectSingleNode("index"); XmlNode endIndex = violationNode.SelectSingleNode("endIndex"); XmlNode startLine = violationNode.SelectSingleNode("startLine"); XmlNode startColumn = violationNode.SelectSingleNode("startColumn"); XmlNode endLine = violationNode.SelectSingleNode("endLine"); XmlNode endColumn = violationNode.SelectSingleNode("endColumn"); // Create a Rule object representing this data. Rule rule = new Rule( ruleName.InnerText, nameSpace.InnerText, ruleCheckId.InnerText, context.InnerText, Convert.ToBoolean(warning.InnerText, CultureInfo.InvariantCulture)); Violation violation; if (startLine != null && startColumn != null && endLine != null && endColumn != null) { CodeLocation location = new CodeLocation( Convert.ToInt32(index.InnerText, null), Convert.ToInt32(endIndex.InnerText, null), Convert.ToInt32(startColumn.InnerText, null), Convert.ToInt32(endColumn.InnerText, null), Convert.ToInt32(startLine.InnerText, null), Convert.ToInt32(endLine.InnerText, null)); // Create a Violation object representing this data. violation = new Violation(rule, sourceCode, location, context.InnerText); } else { // Create a Violation object representing this data. violation = new Violation(rule, sourceCode, Convert.ToInt32(lineNumber.InnerText, null), context.InnerText); } this.AddViolation(violation); } } } catch (ArgumentException) { success = false; } catch (XmlException) { success = false; } catch (FormatException) { success = false; } catch (OverflowException) { success = false; } return(success); }
/// <summary> /// Indicates whether to skip analysis on the given document. /// </summary> /// <param name="sourceCode"> /// The sourceCode to check. /// </param> /// <returns> /// Returns true to skip analysis on the document. /// </returns> public virtual bool SkipAnalysisForDocument(SourceCode sourceCode) { Param.Ignore(sourceCode); return(false); }
/// <summary> /// Called when a violation is found. /// </summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void CoreViolationEncountered(object sender, ViolationEventArgs e) { Param.Ignore(sender, e); lock (this) { // Create the violation element. XmlElement violation = this.violations.CreateElement("Violation"); XmlAttribute attrib = null; // Add the element section if it's not empty. if (e.Element != null) { attrib = this.violations.CreateAttribute("Section"); attrib.Value = CreateSafeSectionName(e.Element.FullyQualifiedName); violation.Attributes.Append(attrib); } // Add the line number. attrib = this.violations.CreateAttribute("LineNumber"); attrib.Value = e.LineNumber.ToString(CultureInfo.InvariantCulture); violation.Attributes.Append(attrib); // Get the source code that this element is in. SourceCode sourceCode = e.SourceCode; if (sourceCode == null && e.Element != null && e.Element.Document != null) { sourceCode = e.Element.Document.SourceCode; } // Add the source code path. if (sourceCode != null) { attrib = this.violations.CreateAttribute("Source"); attrib.Value = sourceCode.Path; violation.Attributes.Append(attrib); } // Add the rule namespace. attrib = this.violations.CreateAttribute("RuleNamespace"); attrib.Value = e.Violation.Rule.Namespace; violation.Attributes.Append(attrib); // Add the rule name. attrib = this.violations.CreateAttribute("Rule"); attrib.Value = e.Violation.Rule.Name; violation.Attributes.Append(attrib); // Add the rule ID. attrib = this.violations.CreateAttribute("RuleId"); attrib.Value = e.Violation.Rule.CheckId; violation.Attributes.Append(attrib); violation.InnerText = e.Message; this.violations.DocumentElement.AppendChild(violation); this.violationCount++; } // Forward event this.OnViolationEncountered(new ViolationEventArgs(e.Violation)); }
/// <summary> /// Parses the given file. /// </summary> /// <param name="sourceCode">The source code to parse.</param> /// <param name="passNumber">The current pass number.</param> /// <param name="document">The parsed representation of the file.</param> /// <returns>Returns false if no further analysis should be done on this file, or /// true if the file should be parsed again during the next pass.</returns> public override bool ParseFile(SourceCode sourceCode, int passNumber, ref ICodeDocument document) { Param.RequireNotNull(sourceCode, "sourceCode"); Param.RequireGreaterThanOrEqualToZero(passNumber, "passNumber"); Param.Ignore(document); // The document is parsed on the first pass. On any subsequent passes, we do not do anything. if (passNumber == 0) { try { using (TextReader reader = sourceCode.Read()) { // Create the document. if (reader == null) { this.AddViolation(sourceCode, 1, Rules.FileMustBeReadable); } else { CsLanguageService languageService = new CsLanguageService(); document = new CsDocumentWrapper( this, sourceCode, languageService.CreateCodeModel(reader, sourceCode.Name, sourceCode.Path)); } } } catch (SyntaxException syntaxex) { this.AddViolation(sourceCode, syntaxex.LineNumber, Rules.SyntaxException, syntaxex.Message); document = null; } } return false; }
public void DoWork(object sender) { Param.Ignore(sender); StyleCopTrace.In(sender); // This flag will indicated whether any source code documents need to passed through // another round of analysis after this one is completed. this.complete = true; SourceCode sourceCode = null; try { // Keep looping until all the source code documents have been processed. while (!this.data.Core.Cancel) { DocumentAnalysisStatus documentStatus; lock (this.data) { // Get the next document to analyze. sourceCode = this.data.GetNextSourceCodeDocument(); if (sourceCode == null) { // There are no more documents. Break out of the loop. break; } // Get the status object for this document. documentStatus = this.data.GetDocumentStatus(sourceCode); Debug.Assert(documentStatus != null, "There is no DocumentStatus for the given SourceCode."); } // If this is the first time we have seen this document, prepare it for analysis. if (!documentStatus.Initialized) { // If the document does not exist, or if the document's analysis data can // be loaded from the results cache, mark the document as completed. if (!sourceCode.Exists || this.LoadSourceCodeFromResultsCache(sourceCode)) { documentStatus.Complete = true; } // Note that the document status has been initialized now. documentStatus.Initialized = true; } // Check whether this document needs further parsing. if (!documentStatus.Complete) { this.ParseAndAnalyzeDocument(sourceCode, documentStatus); } } } catch (OutOfMemoryException) { // Do not catch out of memory exceptions. throw; } catch (ThreadAbortException) { // The thread is being aborted. Stop this thread from doing any additional analysis. } catch (Exception ex) { // Catch exceptions from the parser and analyzer modules. System.Diagnostics.Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Exception occurred: {0}, {1}", ex.GetType(), ex.Message)); this.data.Core.CoreViolations.AddViolation(sourceCode, 1, Rules.ExceptionOccurred, ex.GetType(), FormatExceptionMessage(ex)); // Do not re-throw the exception as this can crash Visual Studio or the build system that StyleCop is running under. } finally { // Fire the completion event if necessary. When running under Visual Studio using MSBuild, the standard // completion event from the BackgroundWorker class does not get fired. The reason is unknown. We fire // our own event instead to get around this problem. if (this.ThreadCompleted != null) { this.ThreadCompleted(this, new EventArgs()); } } StyleCopTrace.Out(); }
/// <summary> /// Parses and analyzes the given document. /// </summary> /// <param name="sourceCode"> /// The document to parse and analyze. /// </param> /// <param name="documentStatus"> /// The current status of the documents. /// </param> private void ParseAndAnalyzeDocument(SourceCode sourceCode, DocumentAnalysisStatus documentStatus) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(documentStatus, "documentStatus"); StyleCopTrace.In(sourceCode, documentStatus); // Signal the output for this document. this.data.Core.SignalOutput( MessageImportance.Low, string.Format(CultureInfo.CurrentCulture, "Pass {0}: {1}", this.data.PassNumber + 1, GetSignalOutputGetText(sourceCode))); // Extract the document to parse. CodeDocument parsedDocument = documentStatus.Document; // Get or load the analyzer list. IEnumerable <SourceAnalyzer> analyzers = sourceCode.Settings.EnabledAnalyzers; // Parse the document. bool parsingCompleted; try { parsingCompleted = !sourceCode.Parser.ParseFile(sourceCode, this.data.PassNumber, ref parsedDocument); } catch (Exception) { string details = string.Format( CultureInfo.CurrentCulture, "Exception thrown by parser '{0}' while processing '{1}'.", sourceCode.Parser.Name, sourceCode.Path); this.data.Core.SignalOutput(MessageImportance.High, details); throw; } if (parsingCompleted) { if (parsedDocument == null) { string format = string.Format(CultureInfo.CurrentCulture, "Skipping: {0} - {1}", sourceCode.Project.Location.SubstringAfterLast('\\'), GetRelativeFileName(sourceCode)); this.data.Core.SignalOutput(MessageImportance.Normal, format); documentStatus.Complete = true; } else if (this.TestAndRunAnalyzers(parsedDocument, sourceCode.Parser, analyzers, this.data.PassNumber)) { // Analysis of this document is completed. documentStatus.Complete = true; // Save the cache for this document and dispose it. if (this.data.ResultsCache != null && sourceCode.Project.WriteCache) { this.data.ResultsCache.SaveDocumentResults(parsedDocument, sourceCode.Parser, sourceCode.Settings.WriteTime); } parsedDocument.Dispose(); parsedDocument = null; } } if (!documentStatus.Complete) { // Analysis of this document is not complete, so we will need to // perform another round of analysis after this one is finished. this.complete = false; // Cache the document if there is one. if (parsedDocument != null) { documentStatus.Document = parsedDocument; } } StyleCopTrace.Out(); }
public abstract bool ParseFile(SourceCode sourceCode, int passNumber, ref ICodeDocument document);
/// <summary> /// Parses a source code document. /// </summary> /// <param name="sourceCode"> /// The source code to parse. /// </param> /// <param name="passNumber"> /// The current pass number. /// </param> /// <param name="document"> /// The parsed representation of the file. /// </param> /// <returns> /// Returns false if no further parsing should be done on this file. /// </returns> public override bool ParseFile(SourceCode sourceCode, int passNumber, ref CodeDocument document) { Param.Ignore(sourceCode, passNumber, document); throw new NotImplementedException(); }
/// <summary> /// Parses a source code document. /// </summary> /// <param name="sourceCode">The source code to parse.</param> /// <param name="passNumber">The current pass number.</param> /// <param name="document">The parsed representation of the file.</param> /// <returns>Returns false if no further analyzation should be done on this file.</returns> public override bool ParseFile(SourceCode sourceCode, int passNumber, ref ICodeDocument document) { Param.Ignore(sourceCode, passNumber, document); throw new NotImplementedException(); }
/// <summary> /// Initializes a new instance of the Violation class. /// </summary> /// <param name="rule"> /// The rule that triggered the violation. /// </param> /// <param name="element"> /// The element that this violation appears in. /// </param> /// <param name="location"> /// The location in the source code where the violation occurs. /// </param> /// <param name="message"> /// The context message for the violation. /// </param> internal Violation(Rule rule, ICodeElement element, CodeLocation location, string message) { Param.AssertNotNull(rule, "rule"); Param.Ignore(element); Param.AssertNotNull(location, "location"); Param.AssertNotNull(message, "message"); this.rule = rule; this.element = element; // The CodeLocation passed in is zero based everywhere in StyleCop for the column. The line number is already 1 based. // We convert is to 1 based here so that are xml reports etc and VisualStudio UI friendly. this.location = new CodeLocation( location.StartPoint.Index, location.EndPoint.Index, location.StartPoint.IndexOnLine + 1, location.EndPoint.IndexOnLine + 1, location.StartPoint.LineNumber, location.EndPoint.LineNumber); // If the location has been passed in we set the linenumber. this.line = location.LineNumber; this.message = message; if (this.element != null && this.element.Document != null) { this.sourceCode = this.element.Document.SourceCode; } this.UpdateKey(); }
/// <summary> /// Parses and analyzes the given document. /// </summary> /// <param name="sourceCode">The document to parse and analyze.</param> /// <param name="documentStatus">The current status of the documents.</param> private void ParseAndAnalyzeDocument(SourceCode sourceCode, DocumentAnalysisStatus documentStatus) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(documentStatus, "documentStatus"); // Signal the output for this document. this.data.Core.SignalOutput( MessageImportance.Low, string.Format(CultureInfo.CurrentCulture, "Pass {0}: {1}...\n", this.data.PassNumber + 1, sourceCode.Name)); // Extract the document to parse. ICodeDocument parsedDocument = documentStatus.Document; // Get or load the analyzer list. IEnumerable <SourceAnalyzer> analyzers = sourceCode.Settings.EnabledAnalyzers; // Parse the document. bool parsingCompleted; try { parsingCompleted = !sourceCode.Parser.ParseFile(sourceCode, this.data.PassNumber, ref parsedDocument); } catch (System.Exception) { string details = string.Format( CultureInfo.CurrentCulture, "Exception thrown by parser '{0}' while processing '{1}'.", sourceCode.Parser.Name, sourceCode.Path); this.data.Core.SignalOutput(MessageImportance.High, details); throw; } if (parsingCompleted) { if (parsedDocument == null) { documentStatus.Complete = true; } else { if (this.data.RunContext.AutoFix) { parsedDocument.ReadOnly = false; } if (this.TestAndRunAnalyzers(parsedDocument, sourceCode.Parser, analyzers, this.data.PassNumber)) { // Analysis of this document is completed. documentStatus.Complete = true; // Save the cache for this document and dispose it. if (parsedDocument != null) { if (this.data.ResultsCache != null && sourceCode.Project.WriteCache) { this.data.ResultsCache.SaveDocumentResults(parsedDocument, sourceCode.Parser, sourceCode.Settings.WriteTime); } // If auto-save is true, then save the doc. if (this.data.RunContext.AutoFix && this.data.AutoSaveMode && parsedDocument.Dirty) { this.SaveDocumentToSource(sourceCode, parsedDocument); } parsedDocument.Dispose(); parsedDocument = null; } } } } if (!documentStatus.Complete) { // Analysis of this document is not complete, so we will need to // perform another round of analysis after this one is finished. this.complete = false; // Cache the document if there is one. if (parsedDocument != null) { documentStatus.Document = parsedDocument; } } }
private bool RegionEndCheckIfBlankOrCurly(SourceCode codeFile, int linenumber, bool allowCurly = true) { var myReader = codeFile.Read(); for (var i = 1; i <= linenumber; i++) { var data = myReader.ReadLine(); if (i == linenumber) { if (data.Trim() == string.Empty || (data.Trim().Contains("}") && allowCurly)) { return true; } } } return false; }
private bool RegionStartCheckIfBlankOrCurly(SourceCode codeFile, int linenumber, bool allowCurly = true) { var myReader = codeFile.Read(); for (var i = 1; i <= linenumber; i++) { var data = myReader.ReadLine(); if (i == linenumber) { //_logFile.WriteLine("LineNumber: {0} -- Text: {1}", linenumber, data); if (data.Trim() == string.Empty || (data.Trim().Contains("{") && allowCurly)) { return true; } } } return false; }
/// <summary> /// Returns the leafname of the source code path. /// </summary> /// <param name="sourceCode"> /// The SourceCode object to use. /// </param> /// <returns> /// The leafname. /// </returns> private static string GetRelativeFileName(SourceCode sourceCode) { string sourceCodePath = sourceCode.Path; string sourceCodeProjectLocation = sourceCode.Project.Location; string outputText = sourceCode.Name; if (sourceCodePath != null && sourceCodeProjectLocation != null && sourceCodePath.StartsWith(sourceCodeProjectLocation, true, CultureInfo.InvariantCulture)) { outputText = sourceCodePath.SubstringAfter(sourceCodeProjectLocation, StringComparison.InvariantCultureIgnoreCase); } return outputText; }
/// <summary> /// Returns the text to use in the signalled output. /// </summary> /// <param name="sourceCode"> /// The SourceCode object to use. /// </param> /// <returns> /// The text to signal. /// </returns> private static string GetSignalOutputGetText(SourceCode sourceCode) { string relativeFileName = GetRelativeFileName(sourceCode); return sourceCode.Project.Location == null ? relativeFileName : string.Format(CultureInfo.CurrentCulture, "{0} - {1}", sourceCode.Project.Location.SubstringAfterLast('\\'), relativeFileName); }
/// <summary> /// Adds a generic violation. /// </summary> /// <param name="sourceCode">The source code document to add the violation to.</param> /// <param name="type">The type of violation to add.</param> /// <param name="line">Line the violation appears on.</param> /// <param name="values">The string values to add to the context string.</param> internal void AddViolation(SourceCode sourceCode, Rule type, int line, params object[] values) { Param.Ignore(sourceCode); Param.AssertNotNull(type, "type"); Param.AssertGreaterThanZero(line, "line"); Param.Ignore(values); // Build up the context string. StringBuilder message = new StringBuilder(); message.AppendFormat(CultureInfo.CurrentCulture, type.Context, values); // Create the violation object and add it to the list. Violation violation = new Violation(type, sourceCode, line, message.ToString()); // Finally, add the violation. this.AddViolation(sourceCode, violation); }
/// <summary> /// Attempts to load results for the given document from the cache. /// </summary> /// <param name="sourceCode"> /// The source code document to load. /// </param> /// <returns> /// Returns true if the results were loaded from the cache. /// </returns> private bool LoadSourceCodeFromResultsCache(SourceCode sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); if (!this.data.IgnoreResultsCache && this.data.Core.Environment.SupportsResultsCache && this.data.ResultsCache != null) { // Check the project to see if the cache should be ignored. ProjectStatus projectStatus = this.data.GetProjectStatus(sourceCode.Project); Debug.Assert(projectStatus != null, "There is no status for the given project."); if (!projectStatus.IgnoreResultsCache) { // Get the last write time for this file. DateTime lastWriteTime = sourceCode.TimeStamp; // Attempt to load the file from the cache. if (this.data.ResultsCache.LoadResults(sourceCode, sourceCode.Parser, lastWriteTime, sourceCode.Project.Settings.WriteTime)) { return true; } } } return false; }
/// <summary> /// Opens the results cache for the given source code document. /// </summary> /// <param name="sourceCode"> /// The source code document. /// </param> /// <param name="parser"> /// The parser that created the document. /// </param> /// <param name="item"> /// Returns the node from the results cache for this code document. /// </param> /// <returns> /// Returns the results cache. /// </returns> private XmlDocument OpenResultsCache(SourceCode sourceCode, SourceParser parser, out XmlNode item) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parser, "parser"); item = null; XmlDocument doc = null; try { lock (this) { // Determine whether this results cache is already in our list. if (this.documentHash.TryGetValue(sourceCode.Project.Location, out doc)) { // Now pull out the section for this source code document. item = doc.DocumentElement.SelectSingleNode( string.Format(CultureInfo.InvariantCulture, "sourcecode[@name=\"{0}\"][@parser=\"{1}\"]", sourceCode.Name, parser.Id)); } else { doc = this.core.Environment.LoadResultsCache(sourceCode.Project.Location); if (doc != null) { // Get the version and make sure it matches. XmlElement node = doc["stylecopresultscache"]["version"]; if (node.InnerText == ResultsCache.Version) { // Now pull out the section for this source code document. item = doc.DocumentElement.SelectSingleNode( string.Format(CultureInfo.InvariantCulture, "sourcecode[@name=\"{0}\"][@parser=\"{1}\"]", sourceCode.Name, parser.Id)); } else { // Since the version does not match, ignore this document. doc = null; } } } } } catch (XmlException) { doc = null; } catch (NullReferenceException) { doc = null; } return doc; }
/// <summary> /// Parses and analyzes the given document. /// </summary> /// <param name="sourceCode"> /// The document to parse and analyze. /// </param> /// <param name="documentStatus"> /// The current status of the documents. /// </param> private void ParseAndAnalyzeDocument(SourceCode sourceCode, DocumentAnalysisStatus documentStatus) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(documentStatus, "documentStatus"); StyleCopTrace.In(sourceCode, documentStatus); // Signal the output for this document. this.data.Core.SignalOutput( MessageImportance.Low, string.Format(CultureInfo.CurrentCulture, "Pass {0}: {1}", this.data.PassNumber + 1, GetSignalOutputGetText(sourceCode))); // Extract the document to parse. CodeDocument parsedDocument = documentStatus.Document; // Get or load the analyzer list. IEnumerable<SourceAnalyzer> analyzers = sourceCode.Settings.EnabledAnalyzers; // Parse the document. bool parsingCompleted; try { parsingCompleted = !sourceCode.Parser.ParseFile(sourceCode, this.data.PassNumber, ref parsedDocument); } catch (Exception) { string details = string.Format( CultureInfo.CurrentCulture, "Exception thrown by parser '{0}' while processing '{1}'.", sourceCode.Parser.Name, sourceCode.Path); this.data.Core.SignalOutput(MessageImportance.High, details); throw; } if (parsingCompleted) { if (parsedDocument == null) { string format = string.Format(CultureInfo.CurrentCulture, "Skipping: {0} - {1}", sourceCode.Project.Location.SubstringAfterLast('\\'), GetRelativeFileName(sourceCode)); this.data.Core.SignalOutput(MessageImportance.Normal, format); documentStatus.Complete = true; } else if (this.TestAndRunAnalyzers(parsedDocument, sourceCode.Parser, analyzers, this.data.PassNumber)) { // Analysis of this document is completed. documentStatus.Complete = true; // Save the cache for this document and dispose it. if (this.data.ResultsCache != null && sourceCode.Project.WriteCache) { this.data.ResultsCache.SaveDocumentResults(parsedDocument, sourceCode.Parser, sourceCode.Settings.WriteTime); } parsedDocument.Dispose(); parsedDocument = null; } } if (!documentStatus.Complete) { // Analysis of this document is not complete, so we will need to // perform another round of analysis after this one is finished. this.complete = false; // Cache the document if there is one. if (parsedDocument != null) { documentStatus.Document = parsedDocument; } } StyleCopTrace.Out(); }
private static CsDocument Parse(SourceCode code, CodeProject project) { CodeDocument codeDocument = null; code.Parser.PreParse(); try { var requiredNextPass = code.Parser.ParseFile(code, 0, ref codeDocument); } catch (ArgumentException) { if (DoNotSuppressExceptions) { throw; } } finally { code.Parser.PostParse(); } return (CsDocument)codeDocument; }