diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d0f7199..5bbc30d 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -10,7 +10,7 @@ Off true latest - Copyright © 2015-2021 Bill Menees + Copyright © 2015-$([System.DateTime]::UtcNow.ToString(`yyyy`)) Bill Menees 1701;1702;1705;SA0001 @@ -19,7 +19,7 @@ - 3.0.4 + 3.0.5 diff --git a/src/Menees.Analyzers/Men002LineTooLong.cs b/src/Menees.Analyzers/Men002LineTooLong.cs index 342348e..3e1c159 100644 --- a/src/Menees.Analyzers/Men002LineTooLong.cs +++ b/src/Menees.Analyzers/Men002LineTooLong.cs @@ -110,12 +110,33 @@ private void HandleSyntaxTree(SyntaxTreeAnalysisContext context) TextSpan lineSpan = line.Span; if (lineSpan.Length * tabSize > maxLength) { - int displayLength = GetLineDisplayLength(line.ToString(), tabSize, maxLength, out int maxIndex); + string lineText = line.ToString(); + int displayLength = GetLineDisplayLength(lineText, tabSize, maxLength, out int maxIndex); if (displayLength > maxLength) { - TextSpan excess = TextSpan.FromBounds(lineSpan.Start + maxIndex, lineSpan.End); - Location location = Location.Create(context.Tree, excess); - context.ReportDiagnostic(Diagnostic.Create(Rule, location, maxLength, displayLength)); + bool report = true; + if (this.settings.AllowLongUriLines) + { + // Ignore if the whole line minus comment delimiters passes Uri.TryCreate(absolute) (e.g., for http or UNC URLs). + string scrubbed = lineText.Trim(); + if (scrubbed.StartsWith("//")) + { + scrubbed = scrubbed.Substring(2).Trim(); + } + else if (scrubbed.StartsWith("/*") && scrubbed.EndsWith("*/")) + { + scrubbed = scrubbed.Substring(2, scrubbed.Length - 4).Trim(); + } + + report = !Uri.TryCreate(scrubbed, UriKind.Absolute, out _); + } + + if (report) + { + TextSpan excess = TextSpan.FromBounds(lineSpan.Start + maxIndex, lineSpan.End); + Location location = Location.Create(context.Tree, excess); + context.ReportDiagnostic(Diagnostic.Create(Rule, location, maxLength, displayLength)); + } } } } diff --git a/src/Menees.Analyzers/Settings.cs b/src/Menees.Analyzers/Settings.cs index f4717cd..e2ca88c 100644 --- a/src/Menees.Analyzers/Settings.cs +++ b/src/Menees.Analyzers/Settings.cs @@ -104,6 +104,7 @@ private Settings(XElement xml) this.MaxPropertyAccessorLines = GetSetting(xml, nameof(this.MaxPropertyAccessorLines), this.MaxPropertyAccessorLines); this.MaxFileLines = GetSetting(xml, nameof(this.MaxFileLines), this.MaxFileLines); this.MaxUnregionedLines = GetSetting(xml, nameof(this.MaxUnregionedLines), this.MaxUnregionedLines); + this.AllowLongUriLines = GetSetting(xml, nameof(this.AllowLongUriLines), this.AllowLongUriLines); XElement typeFileNameExclusionsElement = xml.Element("TypeFileNameExclusions"); if (typeFileNameExclusionsElement != null) @@ -186,6 +187,8 @@ private enum NumberBase public bool HasPreferredTerms => this.preferredTerms.Count > 0; + public bool AllowLongUriLines { get; } = true; + #endregion #region Public Methods @@ -321,13 +324,19 @@ private static Settings LoadSettings(SourceText sourceText) } private static int GetSetting(XElement xml, string elementName, int defaultValue) + => GetSetting(xml, elementName, defaultValue, (string text, out int value) => int.TryParse(text, out value) && value > 0); + + private static bool GetSetting(XElement xml, string elementName, bool defaultValue) + => GetSetting(xml, elementName, defaultValue, bool.TryParse); + + private static T GetSetting(XElement xml, string elementName, T defaultValue, TryParse tryParse) { - int result = defaultValue; + T result = defaultValue; XElement element = xml.Element(elementName); if (element != null) { - if (int.TryParse(element.Value, out int value) && value > 0) + if (tryParse(element.Value, out T value)) { result = value; } @@ -401,5 +410,11 @@ private static Tuple SplitNumericLiteral(string text) } #endregion + + #region Private Delegates + + private delegate bool TryParse(string text, out T value); + + #endregion } } diff --git a/tests/Menees.Analyzers.Test/Men002UnitTests.cs b/tests/Menees.Analyzers.Test/Men002UnitTests.cs index 22d9708..1675684 100644 --- a/tests/Menees.Analyzers.Test/Men002UnitTests.cs +++ b/tests/Menees.Analyzers.Test/Men002UnitTests.cs @@ -38,6 +38,15 @@ class Testing /// Test public Testing() { + // AllowLongUriLines=true + // https://www.amazon.com/Brain-Games%C2%AE-Large-Print-Searches/dp/1640304606/ref=sr_1_2?crid=3KP7CV3HBJADN&keywords=big+long+search+text&qid=1645375366&sprefix=big+long+search+text%2Caps%2C72&sr=8-2 + /* https://www.google.com/maps/place/Yellowstone+National+Park/@44.5854032,-111.0744669,9z/data=!3m1!4b1!4m5!3m4!1s0x5351e55555555555:0xaca8f930348fe1bb!8m2!3d44.427963!4d-110.588455 */ + /* + Brazil weather? + https://weather.com/weather/today/l/63e18eea74a484c42c3921cf52a8fec98113dbb13f6deb7c477b2f453c95b837 + Or: + \\weatherserver\brazil\sao\paulo\today\63e18eea74a484c42c3921cf52a8fec98113dbb13f6deb7c477b2f453c95b837 + */ } } }"; @@ -64,6 +73,7 @@ class TypeName /// public TypeName() // This line is also much too long. { + // GT fans: https://www.amazon.com/yourfanshop?selectedTeamName=Georgia%20Tech%20Yellow%20Jackets&asin=&refinement=popular&team=375636011 } } }"; @@ -80,6 +90,11 @@ public TypeName() // This line is also much too long. Message = "Line must be no longer than 40 characters (now 61).", Locations = new[] { new DiagnosticResultLocation("Test0.cs", 12, 35) } }, + new DiagnosticResult(analyzer) + { + Message = "Line must be no longer than 40 characters (now 149).", + Locations = new[] { new DiagnosticResultLocation("Test0.cs", 14, 32) } + }, }; this.VerifyCSharpDiagnostic(test, expected);